内容网站模板电竞网站建设方案
LeetCode 149:直线上最多的点数
问题本质与核心挑战
给定平面上的点集,需找到 同一直线上最多的点数。核心挑战:
- 如何高效判断三点共线(避免浮点数精度问题);
- 如何统计不同直线上的点数,避免重复计算。
核心思路:斜率归一化 + 哈希表统计
1. 斜率的归一化表示
两点 (x1,y1)
和 (x2,y2)
的斜率可通过 Δx 和 Δy 的最简分数形式 表示,避免浮点数误差:
- 计算
Δx = x2 - x1
,Δy = y2 - y1
; - 求
Δx
和Δy
的最大公约数(GCD),将两者除以 GCD 得到最简形式; - 统一符号:确保相同斜率的表示唯一(如
Δx=-2, Δy=4
和Δx=2, Δy=-4
应归一为同一键)。
2. 哈希表统计
- 枚举每个点作为基准点,统计其他点与该基准点的斜率;
- 用哈希表记录同一斜率的点的数量,结合基准点自身,得到当前直线的最大点数;
- 遍历所有基准点,更新全局最大值。
算法步骤详解(以示例 points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
为例)
步骤 1:特殊情况处理
若点集大小 n ≤ 2
,直接返回 n
(所有点共线)。
步骤 2:枚举基准点,计算斜率
以点 (3,2)
(索引 1
)为基准点,计算其他点的斜率:
其他点 (x,y) | Δx = x-3 | Δy = y-2 | GCD(Δx,Δy) | 最简形式(Δx/GCD, Δy/GCD) | 归一化键(统一符号后) |
---|---|---|---|---|---|
(1,1) | -2 | -1 | 1 | (-2,-1) | 2,1 (Δx<0,取反) |
(5,3) | 2 | 1 | 1 | (2,1) | 2,1 |
(4,1) | 1 | -1 | 1 | (1,-1) | 1,-1 |
(2,3) | -1 | 1 | 1 | (-1,1) | 1,-1 (Δx<0,取反) |
(1,4) | -2 | 2 | 2 | (-1,1) | 1,-1 (Δx<0,取反) |
步骤 3:哈希表统计与最大值更新
- 哈希表记录斜率
2,1
出现2
次,1,-1
出现3
次; - 当前基准点的最大点数为
3 + 1 = 4
(3
个其他点 + 基准点自身),与示例输出一致。
完整代码(Java)
class Solution {public int maxPoints(int[][] points) {int n = points.length;if (n <= 2) return n; // 特殊情况:≤2个点必共线int maxCount = 0;for (int i = 0; i < n; i++) { // 枚举每个基准点Map<String, Integer> slopeMap = new HashMap<>();int currentMax = 0;for (int j = 0; j < n; j++) { // 遍历其他点if (i == j) continue; // 跳过自身int x1 = points[i][0], y1 = points[i][1];int x2 = points[j][0], y2 = points[j][1];int dx = x2 - x1;int dy = y2 - y1;String key = getNormalizedSlope(dx, dy); // 归一化斜率slopeMap.put(key, slopeMap.getOrDefault(key, 0) + 1);currentMax = Math.max(currentMax, slopeMap.get(key));}maxCount = Math.max(maxCount, currentMax + 1); // +1 包含基准点自身}return maxCount;}// 归一化斜率:返回统一表示的键private String getNormalizedSlope(int dx, int dy) {if (dx == 0 && dy == 0) {return "0,0"; // 理论上不会出现(点不重复)}int gcd = computeGCD(dx, dy);dx /= gcd;dy /= gcd;// 统一符号:保证dx非负;若dx为0,保证dy非负if (dx == 0) {dy = Math.abs(dy);} else {if (dx < 0) {dx = -dx;dy = -dy;}}return dx + "," + dy;}// 计算最大公约数(处理负数)private int computeGCD(int a, int b) {a = Math.abs(a);b = Math.abs(b);while (b != 0) {int temp = b;b = a % b;a = temp;}return a;}
}
关键逻辑解析
-
斜率归一化:
- 通过 GCD 约分 Δx 和 Δy,避免重复斜率因倍数关系被误判;
- 统一符号(如
(-2,-1)
转为(2,1)
),确保相同斜率的键唯一。
-
哈希表统计:
- 每个基准点独立统计,避免不同基准点的斜率干扰;
currentMax + 1
包含基准点自身,保证计数正确。
-
时间复杂度:
- 外层遍历
O(n)
个基准点,内层遍历O(n)
个点,哈希表操作O(1)
,总复杂度O(n²)
,可处理n=300
的规模。
- 外层遍历
该方法通过 数学归一化解决精度问题,结合 哈希表高效统计,完美平衡了正确性和效率,是处理“共线点计数”问题的经典方案。