在问 · 算法题解

149. 直线上最多的点数

困难哈希表枚举起点 + 斜率哈希力扣原题 ↗

题目描述

输入数组 points,points[i] = [xi, yi] 是平面上的一个整数坐标点,各点互不相同。

在所有可能的直线中,找出经过给定点最多的那一条,返回它经过的点数。只有一个点时答案为 1。

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

解释:三个点都在直线 y = x 上。

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

解释:[3,2]、[4,1]、[2,3]、[1,4] 都在直线 x + y = 5 上。

数据范围

  • 1 <= points.length <= 300
  • points[i].length == 2
  • -10^4 <= xi, yi <= 10^4
  • 所有点互不相同。

解题思路:枚举起点 + 斜率哈希

一条直线由一个点和一个斜率确定。依次把每个点 i 当作锚点,计算它与后面每个点 j 的方向 (dx, dy),用哈希表统计每个方向出现的次数:同一方向的点和锚点共线。为了避免浮点误差,把 (dx, dy) 除以最大公约数化成最简形式,并统一符号(dx > 0,或 dx = 0 时 dy > 0),这样同一条直线的方向只有一种写法。

为什么正确

处理锚点 i 时,cnt[(dx, dy)] 等于已扫描的点中与 i 在方向 (dx, dy) 上共线的点数;该直线上的点数为 cnt + 1。

复杂度分析

时间 O(n² log C)(log C 来自求最大公约数),空间 O(n)。

易错点

用浮点数 dy/dx 表示斜率会有精度问题,dx = 0 还会除零。另外 (2,-2) 和 (-1,1) 是同一方向,必须约分并统一符号后再作为键。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def maxPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n <= 2:
            return n
        best = 0
        for i in range(n):
            cnt = {}
            x1, y1 = points[i]
            for j in range(i + 1, n):
                dx = points[j][0] - x1
                dy = points[j][1] - y1
                g = math.gcd(dx, dy)
                dx //= g
                dy //= g
                if dx < 0 or (dx == 0 and dy < 0):
                    dx, dy = -dx, -dy
                cnt[(dx, dy)] = cnt.get((dx, dy), 0) + 1
                best = max(best, cnt[(dx, dy)] + 1)
        return best

载入编辑器,自己跑一遍 →

其他解法

两种方法都枚举起点并约分斜率;哈希表计数平均 O(1),整体更快;排序后数相同段不依赖哈希,常数稍大。

解法 2:枚举起点 + 斜率排序 时间 O(n² log n),空间 O(n)

固定起点 i,对每个 j > i 求方向向量 (dx, dy),用最大公约数约分并统一符号。把这些方向向量排序,相同方向会相邻。统计最长的相同段,长度加 1 就是经过点 i 的直线上最多的点数。

不需要哈希表,也不用为二元组设计哈希键,适合不方便用二元组做键的语言。多一个排序的 log n 因子,n 不超过 300 时差别不大。

class Solution:
    def maxPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n <= 2:
            return n
        best = 0
        for i in range(n):
            x1, y1 = points[i]
            dirs = []
            for j in range(i + 1, n):
                dx = points[j][0] - x1
                dy = points[j][1] - y1
                g = math.gcd(dx, dy)
                dx //= g
                dy //= g
                if dx < 0 or (dx == 0 and dy < 0):
                    dx, dy = -dx, -dy
                dirs.append((dx, dy))
            dirs.sort()
            run = 0
            for k in range(len(dirs)):
                if k > 0 and dirs[k] == dirs[k - 1]:
                    run += 1
                else:
                    run = 1
                best = max(best, run + 1)
        return best

哈希表 专题的其他题目

查看 哈希表 全部题目 →