您的位置:首页 > 其它

149. Max Points on a Line

2016-05-04 11:05 381 查看
原题:

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

在一个二维平面上有一个点,求这些点组成的直线中含有最多的点的点的个数。

思路:这个题思路不难,第一步首先找出所有的直线,放到一个HashSet中,使用HashSet是为了去重。第二步遍历所有的直线,每条直线都遍历一遍所有的点,找出在这条直线上的点,并计数。算法的时间复杂度为O(n^2)。

但是在实现的时候,需要注意两个问题,一是如何表示一条直线,二是float/double等的精度问题。

关于如何表示一条直线,我们知道y=ax+b,参数a和b唯一确定一条直线,那就用a和b来表示一条直线。第二个精度问题,我们知道a是斜率,是由除法计算得来的,由于浮点数存在精度问题,我们在验证一个点Point p在不在这直线的时候,把p的坐标带入到y=ax+b时,很容易出现原来本该相等却不相等的情况。这就提示我们不能用浮点数,应该用分数,并且在计算过程中不能出现除法

因此直线用y=(a1/a2)*x+(b1/b2)来表示,即用分子分母互质的分数来代替浮点数。带入一个点验证在不在直线上的时候也不能用除法,整理直线公式得y*a2*b2=a1*b2*x+b1*a2的时候在直线上。

另外因为我们用hashSet来保存直线,所以需要重写equals和hashcode方法。

代码如下:

点的表示

class Point {
int x;int y;
Point() {x = 0;y = 0;}
Point(int a, int b) {x = a;y = b;}
}


直线的表示:

class Line {
int a1,a2,b1,b2;
boolean vertical;  //垂直直线
boolean level;     //水平直线

public Line(int a1, int a2, int b1,int b2,boolean v, boolean l) {
this.a1 = a1;
this.a2 = a2;
this.b1 = b1;
this.b2 = b2;
this.vertical = v;
this.level = l;
}
}
//这里略去equals和hashcode方法的重写。


主函数:

public int maxPoints(Point[] points) {

if (points == null || points.length == 0) {
return 0;
} else if (points.length == 1) {
return 1;
}

HashSet<Line> set = new HashSet<Line>();

//计算出所有的直线,并保存
for (int i = 0; i < points.length; i++) {
for (int j = i + 1; j < points.length; j++) {
set.add(genLine(points[i], points[j]));
}
}

int maxNum = Integer.MIN_VALUE;
for (Line l : set) {
int count = 0;
for (int i = 0; i < points.length; i++) {
if (onLine(l, points[i])) {
count++;
}
}
if (count > maxNum) {
maxNum = count;
}
}

return maxNum;
}

//判断点在不在直线上
public boolean onLine(Line l, Point p) {

if (l.level) {
if(p.y==l.b1){return true;}
return false;
}
if (l.vertical) {
if(p.x==l.b1){return true;}
return false;
}

int left = p.y*l.a2*l.b2;
int right = l.a1*p.x*l.b2+l.b1*l.a2;

if(left==right){
return true;
}

return false;
}

//两点产生一条直线
public Line genLine(Point p1, Point p2) {
if (p1.x == p2.x) { // 垂直的
return new Line(0, 0, p1.x,0,true, false);
}
if (p1.y == p2.y) {
return new Line(0, 0, p1.y,0,false, true);
}

int a1 = p1.y-p2.y;
int a2 = p1.x-p2.x;
int ga = gcd(Math.max(a1, a2),Math.min(a1, a2));
a1 /= ga;
a2 /= ga;

int b1 = a2*p1.y-a1*p1.x;
int b2 = a2;
int gb = gcd(Math.max(b1, b2),Math.min(b1, b2));
b1 /= gb;
b2 /= gb;

return new Line(a1, a2, b1,b2, false, false);
}

//欧几里德算法计算公约数
public int gcd(int a, int b) {
if (b == 0) {
return a;
}
return gcd(b, a % b);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: