LeetCode Top Interview Questions 149. Max Points on a Line (Java版; Hard)

welcome to my blog

LeetCode Top Interview Questions 149. Max Points on a Line (Java版; Hard)

题目描述
Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

Example 1:

Input: [[1,1],[2,2],[3,3]]
Output: 3
Explanation:
^
|
|        o
|     o
|  o  
+------------->
0  1  2  3  4
Example 2:

Input: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
Output: 4
Explanation:
^
|
|  o
|     o        o
|        o
|  o        o
+------------------->
0  1  2  3  4  5  6
第一次做; 核心: 用分数表示斜率; 根据两个点的四种关系进行讨论; 夯实基础: 辗转相除法求最大公因数
/*
核心1:要用分数表示斜率, 不用能小数, 因为会有精度损失; 
核心2:如何统计共线的点的个数
重要基础: 求两个树的最大公因数, 递归; 辗转相除法
*/
class Solution {
    public int maxPoints(int[][] points) {
        if(points==null || points.length==0 || points[0]==null || points[0].length==0)
            return 0;
        //小于等于两个点, 直接返回点的数量即可
        if(points.length<=2)
            return points.length;
        //key是斜率的分子; value是该斜率的的分母, 以及该分数对应的斜率的个数
        HashMap<Integer, HashMap<Integer, Integer>> map = new HashMap<>();
        //
        int n=points.length;
        int res = 0;
        for(int i=0; i<n-1; i++){
            //共线的4种大可能:两个点重合; 两个点横坐标相同; 两个点纵坐标相同; 两个点横纵坐标都不同
            //考虑points[i]在内, 与points[i]重合的点, 这样的点有多少个
            int sameXY = 1;
            //不考虑points[i]在内, 与points[i]横坐标相同的点, 这样的点有多少个
            int sameX = 0;
            //不考虑points[i]在内, 与points[i]纵坐标相同的点, 这样的点有多少个
            int sameY = 0;
            //line表示: 不考虑points[i]在内, 当和points[i]呈某一斜率, 共线的点最多时, 此时与points[i]共线的点的数量
            int line = 0;
            for(int j=i+1; j<n; j++){
                int dy = points[i][1] - points[j][1];
                int dx = points[i][0] - points[j][0];
                //具体处理共线的4中可能
                if(dx==0 && dy==0)
                    sameXY++;
                else if(dx==0 && dy!=0)
                    sameX++;
                else if(dx!=0 && dy==0)
                    sameY++;
                else{
                    int gc = gcd(dy, dx);
                    //斜率化简后的分子
                    int numerator = dy/gc;
                    //斜率化简后的分母
                    int denominator = dx/gc;
                    if(!map.containsKey(numerator))
                        map.put(numerator, new HashMap<Integer,Integer>());
                    HashMap<Integer, Integer> hm = map.get(numerator);
                    if(!hm.containsKey(denominator))
                        hm.put(denominator, 0);
                    hm.put(denominator, hm.get(denominator)+1);
                    /*
                    * 核心: 不能在这里更新res, 这里应该记录和points[i]构成非0斜率的点的数量最大值, 然后在内循环结束后再更新res, 
                    * 否则无法通过示例:[[0,0],[1,1],[0,0]], 正确输出:3; 错误输出2, 因为在这里更新res的时候还没有遇到第二个[0,0], 
                    * 遇到第二个[0,0]时, 所以少考虑了一个重复点
                    * */
                    line = Math.max(line, hm.get(denominator));
                }
            }
            //清空map, 因为map中的数据仅对points[i]有效
            map.clear();
            //更新结果; 找出sameX,sameY,line中的最大值, 然后加上sameXY作为points[i]时的最大值, 如果该最大值比res大就更新res
            res = Math.max(res, Math.max(sameX, Math.max(sameY, line)) + sameXY);
        }
        return res;
    }
    public int gcd(int a, int b){
        return b==0? a : gcd(b, a%b);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值