The "Max Points on a Line" problem asks you to determine the maximum number of points that lie on the same straight line, given a set of points in a 2D plane. Each point is represented as an integer pair [x, y]
. The input is an array points
where points[i] = [x_i, y_i]
.
Your task is to return an integer representing the maximum number of points that can be found on a single straight line.
At first glance, the brute-force approach comes to mind: for every pair of points, check how many other points are collinear with them. However, this would involve checking all possible lines defined by every pair of points and counting, which is computationally expensive.
To optimize, we can observe that:
We solve the problem by iterating through each point and, for each, computing the slope it forms with every other point. We use a hash map (dictionary) to count how many times each slope occurs. The steps are:
i
:
i
).j
:
j
is the same as i
, increment duplicates.i
and j
:
i
is the highest slope count plus duplicates (including i
itself).We repeat this process for every point and return the global maximum.
Let's use the input points = [[1,1],[2,2],[3,3],[4,2],[5,1]]
.
[1,1]
:
[2,2]
: slope = (2-1)/(2-1) = 1[3,3]
: slope = (3-1)/(3-1) = 1[4,2]
: slope = (2-1)/(4-1) = 1/3[5,1]
: slope = (1-1)/(5-1) = 0[1,1]
: 2 (for slope 1) + 1 (itself) = 3[2,2]
:
[2,2]
: 1 + 1 = 2[3,3]
:
[3,3]
: 1 + 1 = 2[4,2]
and [5,1]
:
Brute-force approach:
The key insight is that collinear points share the same slope with respect to a fixed anchor. By iterating through each point and counting the number of points with the same slope, we efficiently find the largest set of collinear points. Using hash maps for slope counting, and representing slopes as reduced fractions, ensures accuracy and speed. This approach is both elegant and efficient, reducing the naive cubic complexity to quadratic.
from collections import defaultdict
from math import gcd
class Solution:
def maxPoints(self, points):
if not points:
return 0
n = len(points)
result = 1
for i in range(n):
slopes = defaultdict(int)
duplicates = 0
max_points = 0
x1, y1 = points[i]
for j in range(i + 1, n):
x2, y2 = points[j]
dx = x2 - x1
dy = y2 - y1
if dx == 0 and dy == 0:
duplicates += 1
continue
g = gcd(dx, dy)
# Reduce the slope to its simplest form
slope = (dy // g, dx // g)
slopes[slope] += 1
max_points = max(max_points, slopes[slope])
result = max(result, max_points + duplicates + 1)
return result
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <utility>
using namespace std;
class Solution {
public:
int maxPoints(vector<vector<int>>& points) {
if (points.empty()) return 0;
int n = points.size(), result = 1;
for (int i = 0; i < n; ++i) {
unordered_map<long long, int> slope_count;
int duplicates = 0, max_points = 0;
for (int j = i + 1; j < n; ++j) {
int dx = points[j][0] - points[i][0];
int dy = points[j][1] - points[i][1];
if (dx == 0 && dy == 0) {
++duplicates;
continue;
}
int g = gcd(dx, dy);
dx /= g;
dy /= g;
// To avoid hash collision, combine dx and dy into one key
long long key = ((long long)dx) * 1000000007 + dy;
slope_count[key]++;
max_points = max(max_points, slope_count[key]);
}
result = max(result, max_points + duplicates + 1);
}
return result;
}
private:
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
};
import java.util.*;
class Solution {
public int maxPoints(int[][] points) {
if (points.length == 0) return 0;
int n = points.length, result = 1;
for (int i = 0; i < n; i++) {
Map<String, Integer> slopeMap = new HashMap<>();
int duplicates = 0, maxPoints = 0;
for (int j = i + 1; j < n; j++) {
int dx = points[j][0] - points[i][0];
int dy = points[j][1] - points[i][1];
if (dx == 0 && dy == 0) {
duplicates++;
continue;
}
int g = gcd(dx, dy);
dx /= g;
dy /= g;
String slope = dx + "/" + dy;
slopeMap.put(slope, slopeMap.getOrDefault(slope, 0) + 1);
maxPoints = Math.max(maxPoints, slopeMap.get(slope));
}
result = Math.max(result, maxPoints + duplicates + 1);
}
return result;
}
private int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
}
function maxPoints(points) {
if (points.length === 0) return 0;
let n = points.length, result = 1;
function gcd(a, b) {
return b === 0 ? a : gcd(b, a % b);
}
for (let i = 0; i < n; i++) {
let slopes = {};
let duplicates = 0, maxPoints = 0;
let [x1, y1] = points[i];
for (let j = i + 1; j < n; j++) {
let [x2, y2] = points[j];
let dx = x2 - x1, dy = y2 - y1;
if (dx === 0 && dy === 0) {
duplicates++;
continue;
}
let g = gcd(dx, dy);
let slope = (dy / g) + '/' + (dx / g);
slopes[slope] = (slopes[slope] || 0) + 1;
maxPoints = Math.max(maxPoints, slopes[slope]);
}
result = Math.max(result, maxPoints + duplicates + 1);
}
return result;
}