Max Points on a Line
来源:互联网 发布:js 判断函数是否定义 编辑:程序博客网 时间:2024/05/05 03:02
https://oj.leetcode.com/problems/max-points-on-a-line/
Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
public int maxPoints(Point[] points)
一条直线的表达方式有好几种,一般比较常见的就是y = kx + c 或者ax + by + c = 0
一种O(N^2)的做法是基于某一个起始点,然后和其他点进行比较,对于每一个起始点,我们维护一个哈希表,键放的东西是用来表达斜率k或者a和b,因为都是同一个起始点,所以起始就完全不需要考虑作为偏移量的常量C了。所以简单来说,在这种做法里,因为每两个点都可以得到一个k或者a和b,在不考虑偏移量的情况下,斜率相同就可以被认为是同一条直线上的。然后遍历所有点作为起始点就可以了。
基于这个算法,需要解决的就是如何在哈希表里去表达这个斜率了。每一个起始点都有自己的哈希表,键放的是斜率的表达方式,值放的就是一个结果数量。在这个过程里找到最大的结果数量并返回就可以。如上面所说,表达式有两种, y = kx + c,或者 ax + by + c = 0。 c我们已经不用管了。那么就有起码两种解决方式了。
第一种,键值那里放的是一个k,double值。这个k的求值方法为(y2 - y1)/(x2 - x1),这里要处理的边界情况有两个,首先显而易见的是x2 == x1的情况。所以我们除了哈希表以外,还需要一个临时变量去处理这个,然后第二个边界情况是不那么显而易见的,那就是y2 == y1的情况。事实上本身这个情况是不那么需要处理的。但是在Java里(c++里没验证过),Double值0和-0是不一样的。所以即使y2 == y1,x2 > x1和x1 > x2时上述表达式求出的斜率是不同的。。这样就错了。所以这也是一个特殊情况。还有一个最特殊的情况就是重复点。判断完这三个特殊情况就可以进行正常的判断了。给出代码如下:
public int maxPoints(Point[] points) { int res = 0; for(int i = 0; i < points.length; i++){ HashMap<Double, Integer> k_counter = new HashMap<Double, Integer>(); int same_x = 0, same_y = 0, same_point = 1; int cur_res = 0; for(int j = i + 1; j < points.length; j++){ if(points[j].x == points[i].x && points[i].y == points[j].y){ same_point++; }else if(points[j].x == points[i].x){ same_x++; }else if(points[j].y == points[i].y){ same_y++;// same_y 必须要的原因是在double里,0.0 和 -0.0是不一样的。所以Wrong Answer最后一个case无法过就是如此。 }else{ Double k = (points[j].y - points[i].y) / (double)(points[j].x - points[i].x); k_counter.put(k, k_counter.containsKey(k) ? k_counter.get(k) + 1 : 1); cur_res = Math.max(cur_res, k_counter.get(k)); } } res = Math.max(res, Math.max(cur_res, Math.max(same_x, same_y)) + same_point); } return res; }
第二种就是用一个String来表达ax + by + c = 0中的a和b。这种情况会比上一个做法少一点边界情况的处理,但并不代表不需要处理。
根据表达式的求值方法,ax + by也可以表达为(y1 - y2)x + (x2 - x1)y。也就是实际上我们用y1 - y2和x1 - x2两个值来替换一个k的表达。可是这里我们再来看看一个情况。
x + 2y + 3 = 0 和 2x + 4y + 6 = 0其实是在表达同一条直线,只是第二个公式还需要化简才能转换成第一个表达式。所以实际上我们还需要得到y1 - y2 和 x1 - x2的最大公约数,然后将y1 - y2和x1 - x2同时除以这个公约数,再存放才具备参考价值。关于公约数的求法,参见代码吧。
public int gcd(int a, int b){//这个就是求最大公约数的函数 return (a != 0) ? gcd(b % a, a) : b; } public int maxPoints(Point[] points) { int result = 0; for(int i = 0; i < points.length; i++){ HashMap<String, Integer> map = new HashMap<String, Integer>(); int same_points = 1; int curmax = 0; for(int j = i + 1; j < points.length; j++){ if(points[i].x == points[j].x && points[i].y == points[j].y){ same_points++; }else{ int diffx = points[i].x - points[j].x; int diffy = points[i].y - points[j].y; int gcd = gcd(diffx, diffy); if(diffx * gcd < 0) gcd *= -1; diffx = gcd == 0 ? diffx : diffx / gcd; diffy = gcd == 0 ? diffy : diffy / gcd; String key = diffx + " " + diffy; if(map.containsKey(key)){ int cur_line = map.get(key) + 1; curmax = Math.max(cur_line, curmax); map.put(key, cur_line); }else{ map.put(key, 1); curmax = Math.max(curmax, 1); } } } result = Math.max(result, curmax + same_points); } return result; }
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- Max Points On a Line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- max points on a line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- Max Points on a Line
- LeetCode 解题报告 Two Sum
- android wifi
- UIApplicationDelegate 各事件
- 结构体
- Android UI开发第二十八篇——Fragment中使用左右滑动菜单
- Max Points on a Line
- VelocityTracker简介 速度追踪
- 日本旅游[整理]
- Android UI开发第二十七篇——实现左右划出菜单
- IOS多线程之NSOperation
- oc的属性
- 欢迎使用CSDN-markdown编辑器
- Unsupported major.minor version 51.0解决办法
- 有关Real-time Apply和FAL_SERVER字段的疑问