Before attempting this problem, you should be comfortable with:
Points are collinear if they share the same slope when measured from a common reference point. For each pair of points, we compute the slope and then check how many other points lie on that same line. By fixing two points and iterating through all remaining points to count matches, we can find the maximum number of collinear points. This triple nested loop is simple but has cubic time complexity.
(i, j), compute their slope.k, check if the slope from i to k matches. If so, increment the count.class Solution:
def maxPoints(self, points: List[List[int]]) -> int:
n = len(points)
if n <= 2:
return n
def get_slope(p1, p2):
if p1[0] == p2[0]:
return float("inf")
return (p2[1] - p1[1]) / (p2[0] - p1[0])
res = 1
for i in range(n):
for j in range(i + 1, n):
slope = get_slope(points[i], points[j])
cnt = 2
for k in range(j + 1, n):
if slope == get_slope(points[i], points[k]):
cnt += 1
res = max(res, cnt)
return resInstead of checking every pair and then scanning all other points, we can fix one point and use a hash map to group all other points by their slope relative to the fixed point. Points with the same slope lie on the same line through the fixed point. The largest group size plus one (for the fixed point itself) gives the maximum collinear points for that reference. Repeating this for every point as the reference yields the global maximum.
res to 1 (at least one point exists).i, create a hash map to count slopes.j, compute the slope from i to j and increment its count in the map.res with count + 1 (including point i).res after processing all points.class Solution:
def maxPoints(self, points: List[List[int]]) -> int:
res = 1
for i in range(len(points)):
p1 = points[i]
count = defaultdict(int)
for j in range(i + 1, len(points)):
p2 = points[j]
if p2[0] == p1[0]:
slope = float("inf")
else:
slope = (p2[1] - p1[1]) / (p2[0] - p1[0])
count[slope] += 1
res = max(res, count[slope] + 1)
return resFloating point slopes can introduce precision errors. To avoid this, we represent the slope as a reduced fraction using the GCD of the differences in x and y coordinates. By storing slopes as pairs (or strings) of integers rather than floating point numbers, we eliminate rounding issues. This approach maintains the same algorithmic structure as the previous solution but with more robust comparisons.
2 or fewer points, return the count directly.i, create a hash map keyed by the normalized slope (using GCD reduction).j:dx = x_j - x_i and dy = y_j - y_i.res with the maximum count plus 1.res.class Solution:
def maxPoints(self, points: List[List[int]]) -> int:
if len(points) <= 2:
return len(points)
def gcd(a, b):
return gcd(b, a % b) if b else a
res = 1
for i in range(len(points) - 1):
count = defaultdict(int)
for j in range(i + 1, len(points)):
dx = points[j][0] - points[i][0]
dy = points[j][1] - points[i][1]
g = gcd(dx, dy)
dx //= g
dy //= g
slope = (dx, dy)
count[slope] += 1
res = max(res, max(count.values()) + 1)
return resWhere is the number of points and is the maximum value in the points.
Using floating point division to compute slopes introduces precision errors. Two mathematically equal slopes may compare as unequal due to rounding. For example, 1/3 and 2/6 might not be exactly equal as floats. The solution is to represent slopes as reduced fractions using GCD, storing them as pairs or strings of integers.
When two points have the same x-coordinate, the slope is undefined (division by zero). Forgetting to handle this case causes runtime errors. Use a special value like infinity or a distinct key (such as "inf" or a tuple like (1, 0)) to represent vertical lines in your slope map.
In floating point arithmetic, -0.0 and 0.0 are distinct values but should be treated as equal slopes. Horizontal lines going left-to-right and right-to-left produce 0.0 and -0.0 respectively. When using floating point slopes, normalize -0.0 to 0.0 before using it as a hash key.
When using GCD to reduce fractions, ensure consistent sign handling. The GCD of negative numbers can produce inconsistent signs across different implementations. Normalize by always making the denominator positive, or by making the first non-zero component positive. Otherwise, slopes like (-1, 2) and (1, -2) will be treated as different when they represent the same line.
When counting points with the same slope from a reference point, the count only includes other points, not the reference point itself. The total collinear points is count + 1. Forgetting to add one for the reference point will undercount by one for every line.