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方法。
代码如下:
点的表示
直线的表示:
主函数:
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); }
相关文章推荐
- android安装本地应用,并提示打开还是完成安装
- rsync --daemon模式的实现
- 获取bean的两种方式
- Jsp的内置对象
- Android如何生成公共属性的get,set方法时,去除 成员变量的m前缀
- Android中的Uri
- 博世传感器调试笔记(二)加速度及陀螺仪传感器BMI160
- 猿类的生活
- 分享一款值得分享的写作工具
- 城市列表
- uiwebview不调用webViewDidFinishLoad的解决办法
- git删除文件
- 基础级-多站点配置
- caffe微调网络时的注意事项(持续更新中)
- CentOS7安装FTP服务
- Android自定义View(一)
- GDOI2016总结
- javaScript 填充表单值的方法
- vmware 虚拟网络环境配置
- TV端使用RecyclerView时遇到的问题