Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
给定一个平面及其上面若干个点,求最大的位于同一直线上的点的个数
/**
* Definition for a point.
* class Point {
* int x;
* int y;
* Point() { x = 0; y = 0; }
* Point(int a, int b) { x = a; y = b; }
* }
*/
public int maxPoints(Point[] points) {}
求在同一直线上的点,很容易想到就是求斜率,那么就是算(y1-y2)/(x1-x2),把任意两点的斜率算出来,找到出现次数最大的斜率即可。
注意点:
- 不能直接算出所有两点的斜率然后加总,因为会出现重复计算,比如4个在同一直线上的,那么组合方式就有6种,实际只有4个点,正确的方式应该是对任意一点,求它跟其他所有点形成的斜率出现的最大次数。
- 不能直接用浮点数存储斜率,double也不行,因为斜率有可能无穷大,那么这时需要换另一种方式,以分数形式表达斜率。而分数形式表达斜率,需要约分成最简形式,即求出分子分母的最大公约数,这里可以用辗转相除法求得
- 出现的点有可能是重复点,那么两个重复点可以看做能够形成任意斜率,因此针对每个点计算加总时,要把这种点的重复点也考虑进去。此外还要考虑斜率无穷大时的情况,因为这时分母=0,要特别注意。
public int maxPoints(Point[] points) {
if(points.length == 0){
return 0;
}
int max = 0;
for(int i=0;i<points.length;i++){
Map<Point,Integer>map = new HashMap<Point,Integer>();
int repeatCount = 0;//重复点
boolean maxChange = false;
int count = 0;
for(int j = i+1;j<points.length;j++){
if(points[i].x == points[j].x && points[i].y == points[j].y){//重复点
repeatCount++;
}
else{
boolean contains = false;
//这里的p是用来记录i,j两点的分数形式表示的斜率
Point p = null;
if(points[i].x == points[j].x){
p = new Point(0,1);
}
else if(points[i].y == points[j].y){
p = new Point(1,0);
}
else{
int greaestDiv = greatestDivisor(points[i].y - points[j].y,points[i].x - points[j].x);
p = new Point(
(points[i].y - points[j].y)/greaestDiv,(points[i].x - points[j].x)/greaestDiv);
}
for(Map.Entry<Point, Integer> entry : map.entrySet()){
if(p.x == entry.getKey().x && p.y == entry.getKey().y){
map.put(entry.getKey(), entry.getValue()+1);
contains = true;
count = entry.getValue();
break;
}
}
if(!contains){
map.put(p,1);
count = 1;
}
if(count > max){
max = count;
maxChange = true;
}
}
}
if(repeatCount > max){//最多出现的就是重复点
max = repeatCount;
}
if(maxChange){//内层循环更新了最大值
max += repeatCount;
}
}
return max+1;
}
public int greatestDivisor(int x,int y){
if(x == 0){
return y;
}
else if(Math.abs(x) > Math.abs(y)){
return greatestDivisor(x%y,y);
}
else{
return greatestDivisor(y%x,x);
}
}