【Leetcode】149. Max Points on a Line

题目地址:

https://leetcode.com/problems/max-points-on-a-line/

给定 n n n个二维平面里点的坐标,问最多有多少个点在同一条直线上。

暴力 O ( n 3 ) O(n^3) O(n3)方法可以参考https://blog.csdn.net/qq_46105170/article/details/112556694。下面介绍一个 O ( n 2 ) O(n^2) O(n2)做法。

可以枚举直线上的一个点 c c c,然后看对于每个斜率,别的其他点有多少个share相同的斜率。对于斜率,可以分三种情况:
1、对于与 c c c重合的点,要开一个变量专门存储;
2、对于斜率是无穷大的点,也要开一个变量专门存储;
3、对于别的情况,则开一个哈希表,key存斜率,value存过 c c c且斜率与key相等的点的个数,其中为了精确,斜率我们存分数的分子和分母,并将其标准化一下,比如要求分子分母互素,并且分子一定要非负(如果分子是 0 0 0,则要求分母必须是正数),这样保证分数表示的唯一性。

代码如下:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class Solution {
    
    class Slope {
        // 斜率是n / m
        int n, m;
        
        public Slope(int x, int y) {
            n = x;
            m = y;
            
            int gcd = gcd(n, m);
            n /= gcd;
            m /= gcd;
            
            if (n == 0) {
                m = Math.abs(m);
            } else if (n < 0) {
                n = -n;
                m = -m;
            }
        }
        
        // 求一下x和y的最大公约数
        private int gcd(int x, int y) {
            while (y != 0) {
                int tmp = y;
                y = x % y;
                x = tmp;
            }
            
            return Math.abs(x);
        }
        
        @Override
        public boolean equals(Object o) {
            Slope slope = (Slope) o;
            return n == slope.n && m == slope.m;
        }
        
        @Override
        public int hashCode() {
            return Objects.hash(n, m);
        }
    }
    
    public int maxPoints(int[][] points) {
        if (points == null || points.length == 0) {
            return 0;
        }
        
        int res = 0;
        Map<Slope, Integer> map = new HashMap<>();
        for (int i = 0; i < points.length; i++) {
        	// 遇到与之前的点重合的点则略过
        	if (i > 0 && Arrays.equals(points[i], points[i - 1])) {
                continue;
            }
            
            // dup记录与points[i]重合的点的个数,vert记录与point[i]不重合并且斜率是正无穷的点的个数
            int dup = 0, vert = 0;
            for (int j = i + 1; j < points.length; j++) {
            	// 如果重合则dup累加,如果斜率是正无穷则vert累加
                if (Arrays.equals(points[i], points[j])) {
                    dup++;
                } else if (points[j][0] == points[i][0]) {
                    vert++;
                } else {
                	// 否则说明在当前斜率下,找到了一个点
                    Slope slope = new Slope(points[j][1] - points[i][1], points[j][0] - points[i][0]);
                    map.put(slope, map.getOrDefault(slope, 0) + 1);
                }
            }
            
            // 首先以与points[i]在同一条垂直线的点的总数更新答案
            res = Math.max(res, dup + 1 + vert);
            // 然后以非无穷大的斜率对应的点的个数更新答案
            for (Map.Entry<Slope, Integer> entry : map.entrySet()) {
                res = Math.max(res, dup + 1 + entry.getValue());
            }
            
            // 别忘了清空哈希表
            map.clear();
        }
        
        return res;
    }
}

时空复杂度 O ( n 2 ) O(n^2) O(n2)

你可能感兴趣的:(LC,二分,位运算与数学,hashmap,leetcode)