直线上最多的点数

题目链接

直线上最多的点数

题目描述

直线上最多的点数_第1张图片
直线上最多的点数_第2张图片

注意点

  • points 中的所有点 互不相同
  • points[i].length == 2

解答思路

  • 一条直线的函数为f(x)=ax+b,两个点决定一条直线,也就是决定了f(x)中斜率a和截距b的值,所以考虑使用一个哈希表存储直线中的a和b并记录ab组合对应的数量(也就是点的数量),ab组合最大数量就是本题所需的答案
  • 使用map存储函数及点数量,但是无法直接将直线函数对应的(a, b)直接存储到key中,所以考虑用String将直线函数中的a和b以某种规则组合存储到map中,又因为a和b都有可能是除不尽的小数,所以需要将斜率a转换为分子分母的方式存到key中,即ay_ax,如果直接存(y2 - y1) / (x2 - x1),则如14 / 7和8 / 4不会认为在同一条直线上,所以还需要对(y2 - y1)和(x2 - x1)求出最大公约数,将ay_ax化简,保证后续在map中根据ay_ax寻找直线是准确的
  • 但是对截距b的计算仍然很麻烦,考虑用更巧妙的方法存key方便找到同一条直线上的点:如果已经确定了一个点,始终以该点作为起点去与其他点连成一条直线,如果是同一条直线,则截距b始终都是保持不变的(b = y1 - ax1,a相同b也相同),所以map中只需要存储斜率即可,此时就可以很轻松的判断出同一斜率下有多少个点,这也和双重循环遍历两个点确定直线的思想不冲突

代码

class Solution {
    public int maxPoints(int[][] points) {
        int res = 0;
        for (int i = 0; i < points.length; i++) {
            // 以points[i]为起点每条直线经过的点数量,因为起点已确定,与其他点组成直线时截距b随着斜率a发生变化
            int tmpMax = 0;
            // map对应的key为斜率,value为点数量
            Map<String, Integer> map = new HashMap<>();
            for (int j = i + 1; j < points.length; j++) {
                int x1 = points[i][0], y1 = points[i][1], x2 = points[j][0], y2 = points[j][1];
                int a = x2 - x1, b = y2 - y1;
                int k = gcd(b, a);
                String key = b / k + "_" + a / k;
                int value = map.getOrDefault(key, 0) + 1;
                map.put(key, value);
                tmpMax = Math.max(tmpMax, value);
            }
            res = Math.max(res, tmpMax + 1);
        }
        return res;
    }
    
    // 求最大公约数
    public int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
}

关键点

  • 用map存取斜率和点数量
  • 起点相同,与其他点相连组成的直线函数中的截距b仅由斜率a决定
  • 求最大公约数的方法

你可能感兴趣的:(算法,leetcode,java,算法,数据结构)