一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情。
前言
力扣第149题 直线上最多的点数 如下所示:
给你一个数组 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
一、思路
题目意思很简单,就是求直线上最多的点数。我们知道两个点可以确定一条直线。那么一个很朴素的想法就出来了,我们可以任选两个点,然后看经过这条直线的有多少个点。
大致的步骤如下所示:
- 选择不重复的两个点
- 利用斜率和截距看落在直线上有多少个点
我们知道 y = ax + b,且有 a = (y1 - y2)/(x1 - x2)。也就是说可以通过两个点先求出斜率 a就,再带入一个点求出截距 b。我就是通过如上的方法来判断落在直线上的点的,但是由于斜率是由浮点数存储的,恨不准确,所以没有办法通过下面的这个示例:
于是我换成了乘法,也就是不求具体的斜率了。只要满足 (y'-y1)(x'-x2) =(y'-y2)(x'-x1)(该式子由两点式转换而来的)即可。
如何优化?
你会发现实际运行中会有这种情况:已经选了和 a1 和 a2 两个点,并计算出了经过 a1, a2 直线上的点个数。但是后续的 a2, a3 与经过 a1, a2 是同一条直线。也就是说同一条直线计算了多遍。
那如何避免这种情况呢?我们只需要存储直线斜率就可以了。只要斜率 k1 已经计算过了,就将其放入 哈希表 防止再次计算。
因为浮点数无法正确的表示斜率,所以哈希表中要存储 约分过后的分数,例如 6/3要约分后变为 2/1。
二、实现
实现代码
实现代码中并未使用 哈希表 进行优化,此部分可自己实现
public int maxPoints(int[][] points) {
int ret = 1;
for (int i=0; i<points.length-1; i++){
for (int j=i+1; j<points.length; j++){
ret = Math.max(ret, pointsInLine(i, j, points));
}
}
return ret;
}
public int pointsInLine(int p1, int p2, int[][] points){
int ret = 2;
int[] point1 = points[p1];
int[] point2 = points[p2];
for (int i=0; i<points.length; i++){
if (i == p1 || i == p2)
continue;
// (y-y1)(x-x2) =(y-y2)(x-x1)
if ((points[i][1] - point1[1]) * (points[i][0] - point2[0]) == (points[i][1] - point2[1]) * (points[i][0] - point1[0]))
ret++;
}
return ret;
}
测试代码
public static void main(String[] args) {
int[][] points = {{1,1},{3,2},{5,3},{4,1},{2,3},{1,4}};
int[][] points1 = {{4,5},{4,-1},{4,0}};
new Number149().maxPoints(points1);
}
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~