Problem#
Given two lines on a Cartesian plane, determine whether they intersect. Each line is represented in the form $ax + by + c = 0$.
Examples#
Example 1#
1
2
3
4
5
6
7
Input:
Line 1 : 2 x + 3 y + 4 = 0
Line 2 : 4 x + 6 y + 8 = 0
Output:
True
Explanation:
The lines are the same ( they overlap), so they intersect everywhere.
Example 2#
1
2
3
4
5
6
7
Input:
Line 1 : x + y + 1 = 0
Line 2 : x + y - 2 = 0
Output:
True
Explanation:
The lines are parallel but have different intercepts, so they do not overlap, but they are not the same line. They do not intersect.
Example 3#
1
2
3
4
5
6
7
Input:
Line 1 : x + y + 1 = 0
Line 2 : x - y + 2 = 0
Output:
True
Explanation:
The lines have different slopes, so they intersect at a single point.
Constraints#
Each line is represented by coefficients $(a, b, c)$, all real numbers.
Lines may be identical, parallel, or intersecting.
Solution#
Method 1 – Slope Comparison#
Intuition#
Two lines on a Cartesian plane will intersect unless they are parallel and not coincident. The slope of a line $ax + by + c = 0$ is $-a/b$ (if $b \neq 0$). If the slopes are different, the lines intersect. If the slopes are the same, check if the lines are coincident (identical) or parallel (never meet).
Approach#
For each line, extract coefficients $(a, b, c)$.
Compute the slope for each line as $-a/b$ (handle vertical lines where $b = 0$).
If slopes differ, lines intersect at a single point.
If slopes are the same:
If the lines are coincident (all coefficients proportional), they overlap (infinite intersection).
Otherwise, they are parallel and do not intersect.
Use a small epsilon for floating point comparison.
Code#
Cpp
Go
Java
Kotlin
Python
Rust
Typescript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution {
public :
static constexpr double kEpsilon = 1e-9 ;
bool Intersect (const std:: array< double , 3 >& l1, const std:: array< double , 3 >& l2) {
double a1 = l1[0 ], b1 = l1[1 ], c1 = l1[2 ];
double a2 = l2[0 ], b2 = l2[1 ], c2 = l2[2 ];
// Handle vertical lines
if (std:: abs(b1) < kEpsilon && std:: abs(b2) < kEpsilon) {
return std:: abs(a1 * c2 - a2 * c1) < kEpsilon;
}
double slope1 = (std:: abs(b1) < kEpsilon) ? std:: numeric_limits< double >:: infinity() : - a1 / b1;
double slope2 = (std:: abs(b2) < kEpsilon) ? std:: numeric_limits< double >:: infinity() : - a2 / b2;
if (std:: abs(slope1 - slope2) > kEpsilon) return true;
// Check if lines are coincident
double ratio_a = (std:: abs(a2) > kEpsilon) ? a1 / a2 : 0 ;
double ratio_b = (std:: abs(b2) > kEpsilon) ? b1 / b2 : 0 ;
double ratio_c = (std:: abs(c2) > kEpsilon) ? c1 / c2 : 0 ;
return std:: abs(ratio_a - ratio_b) < kEpsilon && std:: abs(ratio_b - ratio_c) < kEpsilon;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const epsilon = 1e-9
func Intersect (l1 , l2 [3 ]float64 ) bool {
a1 , b1 , c1 := l1 [0 ], l1 [1 ], l1 [2 ]
a2 , b2 , c2 := l2 [0 ], l2 [1 ], l2 [2 ]
if math .Abs (b1 ) < epsilon && math .Abs (b2 ) < epsilon {
return math .Abs (a1 * c2 - a2 * c1 ) < epsilon
}
var slope1 , slope2 float64
if math .Abs (b1 ) < epsilon {
slope1 = math .Inf (1 )
} else {
slope1 = - a1 / b1
}
if math .Abs (b2 ) < epsilon {
slope2 = math .Inf (1 )
} else {
slope2 = - a2 / b2
}
if math .Abs (slope1 - slope2 ) > epsilon {
return true
}
var ratioA , ratioB , ratioC float64
if math .Abs (a2 ) > epsilon {
ratioA = a1 / a2
}
if math .Abs (b2 ) > epsilon {
ratioB = b1 / b2
}
if math .Abs (c2 ) > epsilon {
ratioC = c1 / c2
}
return math .Abs (ratioA - ratioB ) < epsilon && math .Abs (ratioB - ratioC ) < epsilon
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Solution {
private static final double EPSILON = 1e- 9;
public boolean intersect (double [] l1, double [] l2) {
double a1 = l1[ 0] , b1 = l1[ 1] , c1 = l1[ 2] ;
double a2 = l2[ 0] , b2 = l2[ 1] , c2 = l2[ 2] ;
if (Math.abs (b1) < EPSILON && Math.abs (b2) < EPSILON) {
return Math.abs (a1 * c2 - a2 * c1) < EPSILON;
}
double slope1 = Math.abs (b1) < EPSILON ? Double.POSITIVE_INFINITY : - a1 / b1;
double slope2 = Math.abs (b2) < EPSILON ? Double.POSITIVE_INFINITY : - a2 / b2;
if (Math.abs (slope1 - slope2) > EPSILON) return true ;
double ratioA = Math.abs (a2) > EPSILON ? a1 / a2 : 0;
double ratioB = Math.abs (b2) > EPSILON ? b1 / b2 : 0;
double ratioC = Math.abs (c2) > EPSILON ? c1 / c2 : 0;
return Math.abs (ratioA - ratioB) < EPSILON && Math.abs (ratioB - ratioC) < EPSILON;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
private val epsilon = 1e-9
fun intersect (l1: DoubleArray, l2: DoubleArray): Boolean {
val ( a1, b1, c1) = l1
val ( a2, b2, c2) = l2
if (Math .abs(b1) < epsilon && Math .abs(b2) < epsilon) {
return Math .abs(a1 * c2 - a2 * c1) < epsilon
}
val slope1 = if (Math .abs(b1) < epsilon) Double .POSITIVE_INFINITY else -a1 / b1
val slope2 = if (Math .abs(b2) < epsilon) Double .POSITIVE_INFINITY else -a2 / b2
if (Math .abs(slope1 - slope2) > epsilon) return true
val ratioA = if (Math .abs(a2) > epsilon) a1 / a2 else 0.0
val ratioB = if (Math .abs(b2) > epsilon) b1 / b2 else 0.0
val ratioC = if (Math .abs(c2) > epsilon) c1 / c2 else 0.0
return Math .abs(ratioA - ratioB) < epsilon && Math .abs(ratioB - ratioC) < epsilon
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from typing import List
class Solution :
def intersect (self, l1: List[float], l2: List[float]) -> bool:
epsilon = 1e-9
a1, b1, c1 = l1
a2, b2, c2 = l2
if abs(b1) < epsilon and abs(b2) < epsilon:
return abs(a1 * c2 - a2 * c1) < epsilon
slope1 = float('inf' ) if abs(b1) < epsilon else - a1 / b1
slope2 = float('inf' ) if abs(b2) < epsilon else - a2 / b2
if abs(slope1 - slope2) > epsilon:
return True
ratio_a = a1 / a2 if abs(a2) > epsilon else 0.0
ratio_b = b1 / b2 if abs(b2) > epsilon else 0.0
ratio_c = c1 / c2 if abs(c2) > epsilon else 0.0
return abs(ratio_a - ratio_b) < epsilon and abs(ratio_b - ratio_c) < epsilon
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
impl Solution {
pub fn intersect (l1: [f64 ; 3 ], l2: [f64 ; 3 ]) -> bool {
let epsilon = 1e-9 ;
let (a1, b1, c1) = (l1[0 ], l1[1 ], l1[2 ]);
let (a2, b2, c2) = (l2[0 ], l2[1 ], l2[2 ]);
if b1.abs() < epsilon && b2.abs() < epsilon {
return (a1 * c2 - a2 * c1).abs() < epsilon;
}
let slope1 = if b1.abs() < epsilon { f64 ::INFINITY } else { - a1 / b1 };
let slope2 = if b2.abs() < epsilon { f64 ::INFINITY } else { - a2 / b2 };
if (slope1 - slope2).abs() > epsilon {
return true ;
}
let ratio_a = if a2.abs() > epsilon { a1 / a2 } else { 0.0 };
let ratio_b = if b2.abs() > epsilon { b1 / b2 } else { 0.0 };
let ratio_c = if c2.abs() > epsilon { c1 / c2 } else { 0.0 };
(ratio_a - ratio_b).abs() < epsilon && (ratio_b - ratio_c).abs() < epsilon
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution {
intersect (l1 : [number , number , number ], l2 : [number , number , number ]): boolean {
const epsilon = 1 e - 9 ;
const [a1 , b1 , c1 ] = l1 ;
const [a2 , b2 , c2 ] = l2 ;
if (Math.abs (b1 ) < epsilon && Math.abs (b2 ) < epsilon ) {
return Math.abs (a1 * c2 - a2 * c1 ) < epsilon ;
}
const slope1 = Math.abs (b1 ) < epsilon ? Infinity : - a1 / b1 ;
const slope2 = Math.abs (b2 ) < epsilon ? Infinity : - a2 / b2 ;
if (Math.abs (slope1 - slope2 ) > epsilon ) return true ;
const ratioA = Math.abs (a2 ) > epsilon ? a1 / a2 : 0 ;
const ratioB = Math.abs (b2 ) > epsilon ? b1 / b2 : 0 ;
const ratioC = Math.abs (c2 ) > epsilon ? c1 / c2 : 0 ;
return Math.abs (ratioA - ratioB ) < epsilon && Math.abs (ratioB - ratioC ) < epsilon ;
}
}
Complexity#
⏰ Time complexity: O(1)
, since all operations are simple arithmetic and comparisons.
🧺 Space complexity: O(1)
, only a constant number of variables are used.