精度-LeetCode149-直線上最多的點數
阿新 • • 發佈:2018-12-04
題目
給定一個二維平面,平面上有 n 個點,求最多有多少個點在同一條直線上。
示例 1:
輸入: [[1,1],[2,2],[3,3]]
輸出: 3
解釋:
^
|
| o
| o
| o
+------------->
0 1 2 3 4
示例 2:
輸入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
輸出: 4
解釋:
^
|
| o
| o o
| o
| o o
+------------------->
0 1 2 3 4 5 6
思路1
遍歷確定第一個點,遍歷確定第二個點,這兩點確定一條直線。遍歷第三個點是否在這條直線上。
程式碼1
/** * Definition for a point. * class Point { * int x; * int y; * Point() { x = 0; y = 0; } * Point(int a, int b) { x = a; y = b; } * } */ class Solution { public int maxPoints(Point[] points) { if(points.length<=2){ return points.length; } int res=2; // 第一個點 for(int i=0;i<points.length;i++){ boolean[] isused=new boolean[points.length]; isused[i]=true; // 第二個點 for(int j=0;j<points.length;j++){ if(isused[j]){ continue; } int count=2; isused[j]=true; // 第三個點 for(int k=0;k<points.length;k++){ if(isused[k]){ continue; } if(isLine(points[i],points[j],points[k])){ count++; if(res<count){ res=count; } isused[k]=true; }else{ } } } } return res; } // 判斷第三個點是否與前兩個點在一條直線上 public static boolean isLine(Point p1,Point p2,Point p3){ if(p3.x==p1.x && p3.y==p1.y){ return true; } if(p3.x==p2.x && p3.y==p2.y){ return true; } if(p1.x==p2.x){ return p3.x==p1.x; } if(p3.x==p1.x || p3.x==p2.x){ return false; } // 注意精度問題,例如三個點 (0,0) (94911150,94911151) (94911151,94911152) // (double)94911150/(double)94911151的值與(double)94911151/(double)94911152的值竟然是相等的。 // if((double)(p1.y-p2.y)/(double)(p1.x-p2.x)==(double)(p3.y-p2.y)/(double)(p3.x-p2.x)){ // return true; // }else{ // return false; // } // 為解決此問題,可使用BigDecimal解決精度問題,但BigDecimal不讓使用 // 被除數.divide(除數,小數點後保留幾位,四捨五入).toString(); // String b1=new BigDecimal(p1.y-p2.y).divide(new BigDecimal(p1.x-p2.x), 25, RoundingMode.HALF_UP).toString(); // String b2=new BigDecimal(p3.y-p2.y).divide(new BigDecimal(p3.x-p2.x), 25, RoundingMode.HALF_UP).toString(); // if(b1.equals(b2)){ // return true; // }else{ // return false; // } // 為解決此問題,加上 && (double)(p1.y-p2.y)/(double)(p1.x-p2.x)==(double)(p3.y-p1.y)/(double)(p3.x-p1.x),進行雙重判斷. // 雖然能通過測試,但依然不是精確的表示 // if((double)(p1.y-p2.y)/(double)(p1.x-p2.x)==(double)(p3.y-p2.y)/(double)(p3.x-p2.x) && (double)(p1.y-p2.y)/(double)(p1.x-p2.x)==(double)(p3.y-p1.y)/(double)(p3.x-p1.x)){ // return true; // }else{ // return false; // } // 為解決此問題,分子分母進行約分,化為最簡形式比較 int gcd1=gcd(p1.y-p2.y,p1.x-p2.x); int gcd2=gcd(p3.y-p2.y,p3.x-p2.x); if( (p1.y-p2.y)/gcd1 == (p3.y-p2.y)/gcd2 && (p1.x-p2.x)/gcd1 == (p3.x-p2.x)/gcd2){ return true; }else{ return false; } } public static int gcd(int a,int b){ if(b==0){ return a; } return gcd(b,a%b); } }
注意
1.判斷第三個點是否在前兩個點所在的直線上時,即判斷a/b==c/d時,注意精度問題(看程式碼註釋)。正確的做法是,分子分母求最大公約數然後進行約分變為最簡分數再比較,不能用簡單的除法計算。
2.求最大公約數。見程式碼。
思路2
使用map更快。遍歷確定第一個點,遍歷第二個點與第一個點的斜率放入map<斜率,count>。