1. 程式人生 > 其它 >LeetCode-149. 直線上最多的點數

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);
    }
}
Either Excellent or Rusty