leetcode刷题日记-【149. 直线上最多的点数】

191 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第33天,点击查看活动详情

题目描述

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

 

示例 1:

image.png

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

image.png

输入: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 中的所有点 互不相同

解题思路

给定一个二维数组points,假定每一个二维数组中都是一组坐标,求最多在一条直线上的坐标数;

过同一个点且Δx/Δy相同的点一定在同一条直线上;

根据这个性质,可以从前向后遍历points中的所有坐标点,将相同Δx/Δy的坐标放在一个数组中,每次获取坐标数最多的那一组;

一直循环,注意,这里每次循环的元素不需要向前寻找,因为前面已经包含了后面所有元素的组合;

接下来就是Δx/Δy的计算,Δx/Δy是一个分数,所以需要对这个分数进行化简,化简又涉及到求最大公约数;

最大公约数

两个数都能够整除的最大整数,可以通过递归计算两个数的模,直到模等于0即为两个数的最大公约数;

将化简后的值,通过hash表进行存储,key为约分后的分数,value为当前斜率的所有坐标个数;

需要注意的是分母不能为0,所以当Δx或者Δy为0时需要单独处理;当Δx或者Δy为负数时,因为我们最后存的hash表的key为字符串,所以需要将负号放在统一的位置,以防在获取的时候获取不到同一个key;

所以当Δy为负,对两个值进行取反操作,这样就能保证Δy一直是正数。

代码实现

public static int maxPoints(int[][] points) {
    int max = 1;
    int length = points.length;
    for (int i = 0; i < length-1; i++) {
        int[] nowPoint = points[i];
        int x = nowPoint[0];
        int y = nowPoint[1];
        Map<String, Integer> timesMap = new HashMap<>();
        // 向后寻找元素
        for (int j = i+1; j < length; j++) {
            // 计算斜率
            int distanceX = points[j][0] - x;
            int distanceY= points[j][1] - y;
            String key;
            if (distanceX == 0) {
                key = "x";
            } else if (distanceY == 0) {
                key = "y";
            } else {
                if (distanceY < 0) {
                    distanceX = -distanceX;
                    distanceY = -distanceY;
                }
                // 计算最大公约数
                int maxDivisor = findMaxDivisor(distanceX, distanceY);
                // 约分
                distanceX /= maxDivisor;
                distanceY /= maxDivisor;
                key = distanceX + "/" + distanceY;
            }
            // 从map中取值
            Integer times = timesMap.getOrDefault(key, 1);
            timesMap.put(key, ++times);
            max = Math.max(times, max);
        }
    }
    return max;
}

private static int findMaxDivisor(int distanceX, int distanceY) {
    int mini = Math.min(Math.abs(distanceX), Math.abs(distanceY));
    int max = Math.abs(distanceX) == mini ? Math.abs(distanceY) : Math.abs(distanceX);
    int temp = max % mini;
    return temp == 0 ? mini : findMaxDivisor(mini,temp);
}