题目描述
题目链接:leetcode 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
提示:
1 <= points.length <= 300
points[i].length == 2
- 1 0 4 10^4 104 <= xi, yi <= 1 0 4 10^4 104
points 中的所有点 互不相同
解题思路
思路:
两点确定一条直线,枚举所有两个点的组合就可以得到所有可能出现的直线。在确定一条直线后,再枚举这两个点以外的其它点,判断有几个点落在该直线上
实现细节:
1.已知两个点(
x
1
x_{1}
x1,
y
1
y_1
y1)和(
x
2
x_{2}
x2,
y
2
y_2
y2)所在直线,判断点(
x
3
x_{3}
x3,
y
3
y_3
y3)是否在该直线上只需判断
y
3
−
y
1
x
3
−
x
1
\frac{y_3-y_1}{x_3-x_1}
x3−x1y3−y1 和
y
2
−
y
1
x
2
−
x
1
\frac{y_2-y_1}{x_2-x_1}
x2−x1y2−y1是否相等即可
2.为防止上述公式的分母出现为0的特殊情况,可以排除所有铅直线的情况。为了减少后续枚举数,可进一步排除水平线的情况。实现:先遍历一下所有点并将横坐标x(或纵坐标y)放入HashMap中统计个数,x(或y)的个数即为该铅直线(或水平线)上点的个数。后续的枚举只需枚举非水平和非铅直的情况即可。
3.判断两个浮点数x、y是否相等:(x-y)<eps (定义eps时要确保精度)。
Java代码
class Point{
double x ;
double y ;
public Point(int x ,int y){
this.x = (double)x;
this.y = (double)y;
}
}
public class Solution{
final double eps = 0.00000001;//精度
//判断两个浮点数是否相等
public Boolean isEqual(double x, double y) {
return Math.abs(x-y)<eps;
}
//判断两个点所连直线是否水平 或铅直
public Boolean onParallel(Point a, Point b) {
if(isEqual(a.x, b.x) || isEqual(a.y, b.y)) return true;
else return false;
}
//判断三个点是否在一条直线上
public Boolean isLine(Point a, Point b,Point c) {
return isEqual((b.y-a.y)/(b.x-a.x),(c.y-a.y)/(c.x-a.x));
}
public int maxPoints(int[][] points){
int res = 1; //记录答案
HashMap<Integer, Integer>X = new HashMap<Integer, Integer>();
HashMap<Integer, Integer>Y = new HashMap<Integer, Integer>();
//求在同一条水平线或同一条铅直线上点的个数
for(int []key : points)
{
if(!X.containsKey(key[0])) X.put(key[0], 1);
else{
int cnt = X.get(key[0]) +1;
res = Math.max(res, cnt);
X.put(key[0], cnt);
}
if(!Y.containsKey(key[1])) Y.put(key[1], 1);
else{
int cnt = Y.get(key[1]) +1;
res = Math.max(res, cnt);
Y.put(key[1], cnt);
}
}
//先选取两个点,在看第三个点是否在连点所连直线上
int n = points.length;
for(int i = 0; i<n; i++)
{
for(int j=i+1;j<n;j++)
{
Point a = new Point(points[i][0], points[i][1]);
Point b = new Point(points[j][0], points[j][1]);
if(onParallel(a, b)) continue;
int cnt = 2;
for(int k = 0;k<n;k++){
if(k==i || k==j ) continue;
Point c = new Point(points[k][0], points[k][1]);
if(onParallel(a, c) || onParallel(b, c) ) continue;
if(isLine(a, b, c)) cnt++;
}
res = Math.max(res, cnt);
}
}
return res;
}
}