1232. Check If It Is a Straight Line
Problem Description
You are given an array of points in a 2D plane where each point is represented as [x, y]
coordinates. Your task is to determine whether all these points lie on the same straight line.
The input coordinates
is an array where coordinates[i] = [x, y]
represents the x and y coordinates of the i-th point. You need to check if all points in the array form a straight line when plotted on an XY plane and return true
if they do, false
otherwise.
The solution uses the mathematical property that three points (x1, y1)
, (x2, y2)
, and (x, y)
are collinear (lie on the same line) if and only if the cross product of vectors from the first point to the other two points equals zero. This is expressed as: (x - x1) * (y2 - y1) = (y - y1) * (x2 - x1)
.
The algorithm takes the first two points as reference points to define the line, then checks if every subsequent point satisfies the collinearity condition with these two reference points. If any point fails this check, the points don't form a straight line. This approach avoids division operations and handles vertical lines naturally by using cross multiplication instead of calculating slopes directly.
Intuition
When we need to check if points form a straight line, the first thought might be to calculate the slope between consecutive points and verify they're all equal. The slope between two points (x1, y1)
and (x2, y2)
is (y2 - y1) / (x2 - x1)
.
However, this approach has a problem: division by zero when dealing with vertical lines (when x2 - x1 = 0
). We'd need special case handling for vertical lines, making the code more complex.
To avoid division altogether, we can rearrange the slope equality check. If three points are on the same line, the slope from point 1 to point 2 should equal the slope from point 1 to point 3:
(y2 - y1) / (x2 - x1) = (y3 - y1) / (x3 - x1)
By cross-multiplying to eliminate the fractions, we get:
(y2 - y1) * (x3 - x1) = (y3 - y1) * (x2 - x1)
This elegant transformation removes division entirely, naturally handles vertical lines, and avoids floating-point precision issues. We simply pick the first two points as our reference line, then verify that every other point maintains this same relationship. If any point breaks this pattern, we know the points don't all lie on the same straight line.
Learn more about Math patterns.
Solution Approach
The implementation follows a straightforward approach using the cross-multiplication formula we derived:
-
Extract Reference Points: First, we take the first two points from the coordinates array as our reference points
(x1, y1)
and(x2, y2)
. These two points define the line that all other points should lie on. -
Iterate Through Remaining Points: Starting from the third point (index 2), we iterate through all remaining points in the array. For each point
(x, y)
, we need to verify it's collinear with our reference points. -
Apply Collinearity Check: For each point
(x, y)
, we check the condition:(x - x1) * (y2 - y1) != (y - y1) * (x2 - x1)
If this inequality is true, it means the current point doesn't lie on the same line as the reference points, so we immediately return
False
. -
Return Result: If we successfully check all points without finding any that break the collinearity condition, we return
True
, confirming all points form a straight line.
The algorithm has a time complexity of O(n)
where n
is the number of points, as we check each point exactly once. The space complexity is O(1)
since we only use a constant amount of extra variables regardless of input size.
This approach elegantly handles all edge cases including vertical lines, horizontal lines, and diagonal lines without any special case handling, making it both efficient and robust.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with a concrete example to see how the algorithm works.
Example Input: coordinates = [[1,2], [2,3], [3,4], [4,5]]
Let's check if these points form a straight line.
Step 1: Extract Reference Points
- First point (x1, y1) = (1, 2)
- Second point (x2, y2) = (2, 3)
- These two points define our reference line
Step 2: Check Each Remaining Point
For point at index 2: [3, 4]
where (x, y) = (3, 4)
- Calculate left side:
(x - x1) * (y2 - y1) = (3 - 1) * (3 - 2) = 2 * 1 = 2
- Calculate right side:
(y - y1) * (x2 - x1) = (4 - 2) * (2 - 1) = 2 * 1 = 2
- Since
2 == 2
, this point is collinear ✓
For point at index 3: [4, 5]
where (x, y) = (4, 5)
- Calculate left side:
(x - x1) * (y2 - y1) = (4 - 1) * (3 - 2) = 3 * 1 = 3
- Calculate right side:
(y - y1) * (x2 - x1) = (5 - 2) * (2 - 1) = 3 * 1 = 3
- Since
3 == 3
, this point is collinear ✓
Result: All points satisfy the collinearity condition, so we return True
.
These points indeed form a straight line with slope 1 (each x increases by 1, each y increases by 1).
Counter-example: If we had coordinates = [[1,2], [2,3], [3,5]]
- For the third point
[3, 5]
: - Left side:
(3 - 1) * (3 - 2) = 2 * 1 = 2
- Right side:
(5 - 2) * (2 - 1) = 3 * 1 = 3
- Since
2 != 3
, this point is NOT collinear, we'd returnFalse
Solution Implementation
1class Solution:
2 def checkStraightLine(self, coordinates: List[List[int]]) -> bool:
3 """
4 Check if all points in the coordinates list lie on the same straight line.
5
6 Uses cross multiplication to avoid division by zero when checking collinearity.
7 For three points to be collinear: (x - x1) / (x2 - x1) = (y - y1) / (y2 - y1)
8 Cross multiply to get: (x - x1) * (y2 - y1) = (y - y1) * (x2 - x1)
9
10 Args:
11 coordinates: List of [x, y] coordinate pairs
12
13 Returns:
14 True if all points are on the same line, False otherwise
15 """
16 # Extract the first two points as reference points for the line
17 x1, y1 = coordinates[0]
18 x2, y2 = coordinates[1]
19
20 # Check if each remaining point is collinear with the first two points
21 for x, y in coordinates[2:]:
22 # Use cross multiplication to check if the point (x, y) lies on the line
23 # formed by points (x1, y1) and (x2, y2)
24 if (x - x1) * (y2 - y1) != (y - y1) * (x2 - x1):
25 return False
26
27 # All points are collinear
28 return True
29
1class Solution {
2 /**
3 * Checks if all points in the given coordinates array lie on the same straight line.
4 * Uses cross-multiplication to avoid division and handle vertical lines.
5 *
6 * @param coordinates 2D array where each element is [x, y] representing a point
7 * @return true if all points are collinear, false otherwise
8 */
9 public boolean checkStraightLine(int[][] coordinates) {
10 // Get the first two points to establish the reference line
11 int x1 = coordinates[0][0];
12 int y1 = coordinates[0][1];
13 int x2 = coordinates[1][0];
14 int y2 = coordinates[1][1];
15
16 // Check if each subsequent point lies on the same line
17 // Using the formula: (x - x1) / (x2 - x1) = (y - y1) / (y2 - y1)
18 // Cross-multiply to avoid division: (x - x1) * (y2 - y1) = (y - y1) * (x2 - x1)
19 for (int i = 2; i < coordinates.length; i++) {
20 int currentX = coordinates[i][0];
21 int currentY = coordinates[i][1];
22
23 // Calculate the cross products
24 int leftSide = (currentX - x1) * (y2 - y1);
25 int rightSide = (currentY - y1) * (x2 - x1);
26
27 // If cross products are not equal, point is not on the line
28 if (leftSide != rightSide) {
29 return false;
30 }
31 }
32
33 // All points are collinear
34 return true;
35 }
36}
37
1class Solution {
2public:
3 bool checkStraightLine(vector<vector<int>>& coordinates) {
4 // Get the first two points to establish the reference line
5 int x1 = coordinates[0][0];
6 int y1 = coordinates[0][1];
7 int x2 = coordinates[1][0];
8 int y2 = coordinates[1][1];
9
10 // Check if all remaining points are collinear with the first two points
11 // Using cross product formula: (x - x1) * (y2 - y1) == (y - y1) * (x2 - x1)
12 // This avoids division by zero issues when dealing with vertical lines
13 for (int i = 2; i < coordinates.size(); ++i) {
14 int currentX = coordinates[i][0];
15 int currentY = coordinates[i][1];
16
17 // Cross product should be zero for collinear points
18 // If not equal, points are not on the same straight line
19 if ((currentX - x1) * (y2 - y1) != (currentY - y1) * (x2 - x1)) {
20 return false;
21 }
22 }
23
24 // All points are collinear
25 return true;
26 }
27};
28
1function checkStraightLine(coordinates: number[][]): boolean {
2 // Get the first two points to establish the reference line
3 const x1: number = coordinates[0][0];
4 const y1: number = coordinates[0][1];
5 const x2: number = coordinates[1][0];
6 const y2: number = coordinates[1][1];
7
8 // Check if all remaining points are collinear with the first two points
9 // Using cross product formula: (x - x1) * (y2 - y1) == (y - y1) * (x2 - x1)
10 // This avoids division by zero issues when dealing with vertical lines
11 for (let i = 2; i < coordinates.length; i++) {
12 const currentX: number = coordinates[i][0];
13 const currentY: number = coordinates[i][1];
14
15 // Cross product should be zero for collinear points
16 // If not equal, points are not on the same straight line
17 if ((currentX - x1) * (y2 - y1) !== (currentY - y1) * (x2 - x1)) {
18 return false;
19 }
20 }
21
22 // All points are collinear
23 return true;
24}
25
Time and Space Complexity
The time complexity is O(n)
, where n
is the length of the coordinates
array. This is because the algorithm iterates through the coordinates array once, starting from index 2, performing a constant-time operation (the cross-product calculation (x - x1) * (y2 - y1) != (y - y1) * (x2 - x1)
) for each point. Since we examine n - 2
points after the first two reference points, and each check takes O(1)
time, the overall time complexity is O(n)
.
The space complexity is O(1)
. The algorithm only uses a fixed amount of extra space to store the coordinates of the first two points (x1
, y1
, x2
, y2
) and the loop variables (x
, y
). No additional data structures are created that scale with the input size, so the space usage remains constant regardless of how many coordinates are in the input array.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Division by Zero When Using Slope Formula
One of the most common mistakes when solving this problem is attempting to use the traditional slope formula directly:
# WRONG APPROACH - Can cause division by zero
def checkStraightLine(self, coordinates):
x1, y1 = coordinates[0]
x2, y2 = coordinates[1]
# This fails when x2 == x1 (vertical line)
slope = (y2 - y1) / (x2 - x1) # Division by zero error!
for x, y in coordinates[2:]:
current_slope = (y - y1) / (x - x1) # Another potential division by zero
if current_slope != slope:
return False
return True
Why it fails: When dealing with vertical lines where x2 == x1
, the denominator becomes zero, causing a runtime error.
Solution: The provided cross-multiplication approach avoids division entirely by rearranging the equation from (y2 - y1) / (x2 - x1) = (y - y1) / (x - x1)
to (x - x1) * (y2 - y1) = (y - y1) * (x2 - x1)
.
2. Floating Point Precision Issues
Another pitfall occurs when developers try to handle the division by zero case but introduce floating-point comparisons:
# PROBLEMATIC APPROACH - Floating point precision issues
def checkStraightLine(self, coordinates):
x1, y1 = coordinates[0]
x2, y2 = coordinates[1]
for x, y in coordinates[2:]:
# Using division can lead to precision errors
if (x2 - x1) != 0 and (x - x1) != 0:
slope1 = (y2 - y1) / (x2 - x1)
slope2 = (y - y1) / (x - x1)
if slope1 != slope2: # Floating point comparison can be unreliable
return False
return True
Why it fails: Floating-point arithmetic can introduce small rounding errors, making exact equality comparisons unreliable.
Solution: The cross-multiplication method uses only integer arithmetic (assuming integer coordinates), completely avoiding floating-point precision issues.
3. Incorrect Handling of Edge Cases
Some implementations forget to handle special cases like when all points have the same x-coordinate (vertical line) or y-coordinate (horizontal line):
# INCOMPLETE APPROACH - Missing edge case handling
def checkStraightLine(self, coordinates):
if len(coordinates) <= 2:
return True
# Trying to handle vertical/horizontal lines separately
if coordinates[1][0] == coordinates[0][0]: # Vertical line
for point in coordinates[2:]:
if point[0] != coordinates[0][0]:
return False
return True
# ... similar code for horizontal lines
# ... then handle general case
Why it's problematic: This approach requires multiple conditional branches and separate logic for different line orientations, making the code complex and error-prone.
Solution: The cross-multiplication formula naturally handles all cases (vertical, horizontal, and diagonal lines) with a single unified approach, eliminating the need for special case handling.
Which data structure is used in a depth first search?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!