Given an array of points
where points[i] = [x<sub>i</sub>, y<sub>i</sub>]
represents a point on the X-Y plane, return the maximum number of points that lie on the same straight line.
For example:
Input: points = [[1,1],[2,2],[3,3]]
Output: 3
In this case, all three points lie on the same line (y = x), so the answer is 3.
Another example:
Input: points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
Output: 4
In this case, there is no line that contains more than 4 points. A line containing 4 points is possible.
Here are the constraints:
1 <= points.length <= 300
points[i].length == 2
-10<sup>4</sup> <= x<sub>i</sub>, y<sub>i</sub> <= 10<sup>4</sup>
points
are unique.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We need to find the most points that lie on the same straight line. The brute force approach involves checking every possible line that can be formed by any two points, and then counting how many other points fall on that same line.
Here's how the algorithm would work step-by-step:
def max_points_on_a_line(points):
number_of_points = len(points)
if number_of_points <= 2:
return number_of_points
max_points = 0
for i in range(number_of_points):
for j in range(i + 1, number_of_points):
# Consider each pair of points to form a line
points_on_line = 2
for k in range(j + 1, number_of_points):
# Check if any other points lie on the same line
point_a = points[i]
point_b = points[j]
point_c = points[k]
# Check if the cross product is 0 to see if collinear
if (point_b[1] - point_a[1]) * (point_c[0] - point_b[0]) == (point_c[1] - point_b[1]) * (point_b[0] - point_a[0]):
points_on_line += 1
# Update the maximum points found so far
if points_on_line > max_points:
max_points = points_on_line
return max_points
The key is to consider each point as a potential origin and see how many other points fall on the same line emanating from that origin. Instead of exhaustively checking every possible line, we cleverly group points by their slopes relative to our chosen origin point.
Here's how the algorithm would work step-by-step:
def max_points_on_a_line(points):
max_number_of_points = 0
number_of_points = len(points)
for i in range(number_of_points):
slopes = {}
duplicate_points = 1
vertical_points = 0
current_max = 0
for j in range(i + 1, number_of_points):
# Check for duplicate points.
if points[i][0] == points[j][0] and points[i][1] == points[j][1]:
duplicate_points += 1
continue
# Handle vertical lines (division by zero).
if points[i][0] == points[j][0]:
vertical_points += 1
current_max = max(current_max, vertical_points)
continue
slope = (points[j][1] - points[i][1]) / (points[j][0] - points[i][0])
slopes[slope] = slopes.get(slope, 0) + 1
current_max = max(current_max, slopes[slope])
# Update the maximum points on a line from this origin.
max_number_of_points = max(max_number_of_points, current_max + duplicate_points)
return max_number_of_points
Case | How to Handle |
---|---|
Empty input list of points | Return 0, as no points exist to form a line. |
Input list contains only one point | Return 1, as a single point lies on a line by itself. |
Input list contains two points | Return 2, as two points always form a line. |
All points are the same (duplicates) | The slope calculation will result in undefined or NaN, but the equal points should be counted correctly within the same position/duplicate point logic. |
Vertical line (infinite slope) | Handle vertical lines as a special case in the slope calculation to avoid division by zero. |
Floating-point precision issues when calculating slope | Use a tolerance value (epsilon) when comparing slopes to account for potential floating-point errors. |
Large input dataset causing potential memory issues | Ensure the chosen data structures (e.g., hash maps) are efficient in terms of memory usage. |
Integer overflow when calculating slope with very large coordinates | Use a larger data type (e.g., long) to store the numerators and denominators of the slopes to prevent integer overflow. |