直线上最多的点数
难度:
标签:
题目描述
给你一个数组 points
,其中 points[i] = [xi, yi]
表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。
示例 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
-104 <= xi, yi <= 104
points
中的所有点 互不相同
代码结果
运行时间: 51 ms, 内存: 16.2 MB
/*
* 思路:
* 1. 使用Stream API遍历所有点。
* 2. 对每对点计算斜率并统计相同斜率的点数。
* 3. 使用最大公约数简化斜率表示。
*/
import java.util.*;
import java.util.stream.Collectors;
public class MaxPointsOnLineStream {
public int maxPoints(int[][] points) {
if (points.length <= 1) return points.length;
return Arrays.stream(points).mapToInt(point -> {
Map<String, Integer> slopeMap = new HashMap<>();
int duplicates = 1;
int verticals = 0;
for (int[] other : points) {
if (Arrays.equals(point, other)) continue;
int dx = other[0] - point[0];
int dy = other[1] - point[1];
if (dx == 0 && dy == 0) {
duplicates++;
} else if (dx == 0) {
verticals++;
} else {
int gcd = gcd(dx, dy);
dx /= gcd;
dy /= gcd;
String slope = dx + "/" + dy;
slopeMap.merge(slope, 1, Integer::sum);
}
}
int currentMax = slopeMap.values().stream().mapToInt(v -> v).max().orElse(verticals);
return currentMax + duplicates;
}).max().orElse(1);
}
private int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
}
解释
方法:
这个题解是使用哈希表来解决直线上最多的点数问题。具体思路如下:
1. 如果点的个数小于等于2,直接返回点的个数即可,因为2个及以下的点必然在同一条直线上。
2. 对于点数大于2的情况,使用两重循环遍历所有点对。外层循环固定一个点,内层循环遍历其他点。
3. 对于每一对点(x1,y1)和(x2,y2),计算它们所在直线的一般式方程ax+by+c=0的系数a,b,c。
- 如果两点的x坐标相同,则直线方程为x=x1,系数为a=1,b=0,c=-x1。
- 如果两点的y坐标相同,则直线方程为y=y1,系数为a=0,b=1,c=-y1。
- 对于其他情况,可以通过两点式方程推导出a=1,b=(x1-x2)/(y2-y1),c=(x1*y2-x2*y1)/(y1-y2)。
4. 将直线方程的系数(a,b,c)作为键存入哈希表,对应的值为该直线上的点数。
5. 如果当前直线在哈希表中已存在,则将点数加1,并更新res为res和更新后点数的较大值。
6. 如果当前直线不在哈希表中,则将其加入哈希表,初始点数为2。
7. 遍历完所有点对后,res即为所求的最多在同一条直线上的点数。
时间复杂度:
O(n^2)
空间复杂度:
O(n^2)
代码细节讲解
🦆
在哈希表中作为键存储直线的(a, b, c)系数时,如何保证由于浮点数精度问题而导致的不同直线被错误地认为是相同的情况?
▷🦆
代码中对于两点式方程的推导是否存在误差,特别是当y1与y2非常接近但不相等时,如何处理精度问题以确保系数b和c的准确性?
▷🦆
在计算每一对点形成的直线参数时,如果两点很接近但不完全相同,这种方法是否可能会因为数值计算问题而无法准确识别直线?
▷🦆
解决方案中对于点数少于等于2的情况,直接返回点的个数。这在所有输入点都相同的情况下是否仍然适用?
▷