题目链接
直线上最多的点数
题目描述
注意点
- points 中的所有点 互不相同
- points[i].length == 2
解答思路
- 一条直线的函数为f(x)=ax+b,两个点决定一条直线,也就是决定了f(x)中斜率a和截距b的值,所以考虑使用一个哈希表存储直线中的a和b并记录ab组合对应的数量(也就是点的数量),ab组合最大数量就是本题所需的答案
- 使用map存储函数及点数量,但是无法直接将直线函数对应的(a, b)直接存储到key中,所以考虑用String将直线函数中的a和b以某种规则组合存储到map中,又因为a和b都有可能是除不尽的小数,所以需要将斜率a转换为分子分母的方式存到key中,即ay_ax,如果直接存(y2 - y1) / (x2 - x1),则如14 / 7和8 / 4不会认为在同一条直线上,所以还需要对(y2 - y1)和(x2 - x1)求出最大公约数,将ay_ax化简,保证后续在map中根据ay_ax寻找直线是准确的
- 但是对截距b的计算仍然很麻烦,考虑用更巧妙的方法存key方便找到同一条直线上的点:如果已经确定了一个点,始终以该点作为起点去与其他点连成一条直线,如果是同一条直线,则截距b始终都是保持不变的(b = y1 - ax1,a相同b也相同),所以map中只需要存储斜率即可,此时就可以很轻松的判断出同一斜率下有多少个点,这也和双重循环遍历两个点确定直线的思想不冲突
代码
class Solution {
public int maxPoints(int[][] points) {
int res = 0;
for (int i = 0; i < points.length; i++) {
// 以points[i]为起点每条直线经过的点数量,因为起点已确定,与其他点组成直线时截距b随着斜率a发生变化
int tmpMax = 0;
// map对应的key为斜率,value为点数量
Map<String, Integer> map = new HashMap<>();
for (int j = i + 1; j < points.length; j++) {
int x1 = points[i][0], y1 = points[i][1], x2 = points[j][0], y2 = points[j][1];
int a = x2 - x1, b = y2 - y1;
int k = gcd(b, a);
String key = b / k + "_" + a / k;
int value = map.getOrDefault(key, 0) + 1;
map.put(key, value);
tmpMax = Math.max(tmpMax, value);
}
res = Math.max(res, tmpMax + 1);
}
return res;
}
// 求最大公约数
public int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}
}
关键点
- 用map存取斜率和点数量
- 起点相同,与其他点相连组成的直线函数中的截距b仅由斜率a决定
- 求最大公约数的方法