LeetCode-149. 直线上最多的点数

题目来源

149. 直线上最多的点数

题目详情

给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。

示例 1:

输入: points = [[1,1],[2,2],[3,3]]
输出: 3

示例 2:

输入: points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出: 4

提示:

  • 1 <= points.length <= 300
  • points[i].length == 2
  • -104 <= xi, yi <= 104
  • points 中的所有点 互不相同

题解分析

解法一:暴力法

class Solution {
    public int maxPoints(int[][] points) {
        int n = points.length;
        // y1 = kx1 + b
        // y2 = kx2 + b
        // k = (y1-y2) / (x1-x2), b = y1 - x1 * ((y1-y2) / (x1-x2))
        
        int ans = 1;
        for(int i=0; i<n; i++){
            int x1 = points[i][0], y1= points[i][1];
            for(int j=i+1; j<n; j++){
                int x2 = points[j][0], y2= points[j][1];
                int max = 2;
                for(int k=j+1; k<n; k++){
                    int x3 = points[k][0], y3= points[k][1];
                    // 不直接比较两个斜率,而是将除法的比较转换为乘法比较
                    int temp1 = (y2-y1) * (x3-x2);
                    int temp2 = (y3-y2) * (x2-x1);
                    if(temp1 == temp2){
                        max++;
                    }
                }
                ans = Math.max(ans, max);
            }
        }
        return ans;
    }
}

解法二:HashMap优化

  1. 从解法一我们可以看到,这种方法的时间复杂度为\(O(n^3)\),那有什么方法能够减少时间复杂度呢?
  2. 对于本题而言,我们可以从如何判断两个点共线来思考。我们在方法一中是通过遍历剩下所有点来判断它是否和已有的直线共线来判断是否三点共线的。从这里,我们可以看到,我们只需要固定起始点,然后遍历剩下的点,再记录下它们与起始点的斜率,如果斜率相同的汇总在一起,表明这些点一定共线(不需要判断截距了,因为起始点是固定的,这就相当于截距固定了)。
  3. 所以,这里我们可以使用一个HashMap来存储斜率,并在里层循环中,将所有斜率相同的点进行汇总,拥有最多点的直线就是以起始点为开始的最佳直线。
  4. 此外,本题还有一个问题,那就是有可能我们计算的斜率是double型的,直接将其作为key进行存储,有可能会面临精度丢失的问题。那我们应该存储什么呢?从计算斜率的公式出发,k=(y1-y2)/(x1-x2),我们可以存储y1-y2以及x1-x2,这两个结果可以确定斜率。但是,我们也不能直接存储y1-y2以及x1-x2,因为它们之间可以存在倍数的关系,所以我们需要将y1-y2以及x1-x2除尽。
class Solution {
    public int maxPoints(int[][] points) {
        int n = points.length;
        // y1 = kx1 + b
        // y2 = kx2 + b
        // k = (y1-y2) / (x1-x2), b = y1 - x1 * ((y1-y2) / (x1-x2))
        
        int ans = 0;
        for(int i=0; i<n; i++){
            int x1 = points[i][0], y1= points[i][1];
            Map<String,Integer> map = new HashMap<>();
            int max = 0;
            for(int j=i+1; j<n; j++){
                int x2 = points[j][0], y2= points[j][1];
                int ydif = y1-y2;
                int xdif = x1-x2;
                int common = gcd(ydif, xdif);
                String key = Arrays.toString(new int[]{ydif/common, xdif/common});
                int num = map.getOrDefault(key, 0);
                map.put(key, num + 1);
                max = Math.max(max, num+1);
            }
            ans = Math.max(ans , max +1);
        }
        return ans;
    }

    private int gcd(int a, int b){
        return b == 0 ? a : gcd(b, a%b);
    }
}
posted @ 2022-03-06 10:40  Garrett_Wale  阅读(256)  评论(0编辑  收藏  举报