精度-LeetCode149-直线上最多的点数

题目

给定一个二维平面,平面上有 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>。

猜你喜欢

转载自blog.csdn.net/qq_36025975/article/details/83893498