一、题目描述
给定二维平面上的一些点 points,其中:
points[i] = [xi, yi]
表示平面上的一个点 (xi, yi)。
请你求出 最多有多少个点在同一条直线上。
示例 1:
输入:points = [[1,1],[2,2],[3,3]]
输出:3
示例 2:
输入:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出:4
约束:
1 <= points.length <= 300
points[i].length == 2
-10^4 <= xi, yi <= 10^4
points 中所有点互不相同
二、题目思路分析
如果多个点在同一条直线上,那么 它们之间的斜率一定相同。
假设固定一个点 (x1,y1),再选择另一个点 (x2,y2):
slope = (y2 - y1) / (x2 - x1)
如果第三个点 (x3,y3) 满足:
(y2 - y1)/(x2 - x1) = (y3 - y1)/(x3 - x1)
则说明三点共线。
因此可以得到核心思路:
固定一个点
计算它与其他点的斜率
统计相同斜率的数量
最大值 + 1(包括自己)
由于点最多 300 个,因此枚举起点并统计斜率即可。
时间复杂度:
O(n²)
三、解法一:暴力枚举三点(不推荐)
最直接的方法是枚举三个点,判断是否共线。
判断三点共线:
(x2-x1)*(y3-y1) == (x3-x1)*(y2-y1)
C语言实现
int maxPoints(int** points, int pointsSize, int* pointsColSize) {
if (pointsSize <= 2)
return pointsSize;
int max = 2;
for (int i = 0; i < pointsSize; i++) {
for (int j = i + 1; j < pointsSize; j++) {
int count = 2;
for (int k = j + 1; k < pointsSize; k++) {
int x1 = points[i][0];
int y1 = points[i][1];
int x2 = points[j][0];
int y2 = points[j][1];
int x3 = points[k][0];
int y3 = points[k][1];
if ((x2 - x1) * (y3 - y1) == (x3 - x1) * (y2 - y1))
count++;
}
if (count > max)
max = count;
}
}
return max;
}
复杂度
时间复杂度:O(n³)
空间复杂度:O(1)
当 n=300 时可能会超时,因此一般不采用。
四、解法二:斜率统计(推荐)
核心思想:
固定一个点
统计所有斜率
斜率相同 → 在同一直线
但有一个关键问题:
浮点数精度误差
例如:
1/3
2/6
理论上相同,但浮点计算可能不同。
因此需要:
使用最简分数 dy/dx
利用 最大公约数 gcd 进行约分。
例如:
dy = 4
dx = 2
→ 2/1
五、算法步骤
-
枚举每一个点
i -
计算
i与其它点j的斜率(dy,dx) -
用
gcd进行约分 -
统计相同斜率数量
-
更新最大值
六、C语言实现(推荐)
#include <stdlib.h>
int gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
int maxPoints(int** points, int pointsSize, int* pointsColSize) {
if (pointsSize <= 2)
return pointsSize;
int result = 0;
for (int i = 0; i < pointsSize; i++) {
int slopes[600][2];
int count[600] = {0};
int size = 0;
int localMax = 0;
for (int j = i + 1; j < pointsSize; j++) {
int dx = points[j][0] - points[i][0];
int dy = points[j][1] - points[i][1];
int g = gcd(abs(dx), abs(dy));
dx /= g;
dy /= g;
int found = 0;
for (int k = 0; k < size; k++) {
if (slopes[k][0] == dx && slopes[k][1] == dy) {
count[k]++;
if (count[k] > localMax)
localMax = count[k];
found = 1;
break;
}
}
if (!found) {
slopes[size][0] = dx;
slopes[size][1] = dy;
count[size] = 1;
if (count[size] > localMax)
localMax = count[size];
size++;
}
}
if (localMax + 1 > result)
result = localMax + 1;
}
return result;
}
七、复杂度分析
时间复杂度:O(n²)
空间复杂度:O(n)
其中:
外层枚举点
内层统计斜率
八、优化技巧(面试加分)
1 提前结束
如果:
当前最大值 >= 剩余点数
则可以提前退出循环。
2 处理特殊情况
垂直线:
dx = 0
统一表示为:
(0,1)
水平线:
dy = 0
统一表示为:
(1,0)
九、总结
| 方法 | 时间复杂度 | 推荐 |
|---|---|---|
| 暴力枚举 | O(n³) | ❌ |
| 斜率统计 | O(n²) | ✅ |
核心思想:
固定一个点
统计所有斜率
斜率相同 → 共线
通过 gcd 约分避免浮点误差,即可得到最终答案。