算法练习每日一题:直线上最多的点数

149. 直线上最多的点数

给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。

  • 示例 1:

输入: [[1,1],[2,2],[3,3]]

输出: 3

解释:

^
|
|        o
|     o
|  o  
+------------->
0  1  2  3  4
  • 示例 2:

输入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]

输出: 4

解释:

^
|
|  o
|     o        o
|        o
|  o        o
+------------------->
0  1  2  3  4  5  6

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/max-points-on-a-line

class Solution:
    def maxPoints(self, points):
        """
        :type points: List[Point]
        :rtype: int
        """   
        # 如果 points 中元素少于3,也就是两个点,那它们一定在一条直线上
        self.points = points
        n = len(self.points)
        if n < 3:
            return n
        
        max_count = 1
        # 遍历 hash 超出最多的点的线条,找出 count 的最大值 
        for i in range(n - 1):
            max_count = max(self.max_points_on_a_line_containing_point_i(i, n), max_count)
        return max_count
        
    def add_line(self, i, j, count, duplicates):
        """
        画线,判断点是否在一条线上
        普通线条(斜率),记录所在点数
        重复或 180 度线条,记录起点数
        """
        # 转换为座标
        x1 = self.points[i][0]
        y1 = self.points[i][1]
        x2 = self.points[j][0]
        y2 = self.points[j][1]
        # 处理重复的点,平行的线条;注意平行线条斜率无穷大,不存在斜率,需要单独处理
        # 一个点可能在多个线条上,则选择点数最多的那个线条
        if x1 == x2 and y1 == y2:  
            duplicates += 1
        elif y1 == y2:
            self.horisontal_lines += 1
            count = max(self.horisontal_lines, count)
        else:
            slope = (x1 - x2) / (y1 - y2)
            self.lines[slope] = self.lines.get(slope, 1) + 1
            count = max(self.lines[slope], count)
        return count, duplicates
        
    def max_points_on_a_line_containing_point_i(self, i, n):
        """
        计算每条线的最多点数
        """
        # 初始化 dict,只要有 2 个以上的点,则一定有一条线
        self.lines, self.horisontal_lines = {}, 1
        # 编码是从 i + 1 开始的,count 计数默认值应该是 1
        count = 1
        # 与其相同(重复的点),在垂直或平行方向上的点数,默认为 0 
        duplicates = 0
        for j in range(i + 1, n):
            count, duplicates = self.add_line(i, j, count, duplicates)
        return count + duplicates         

题解

  • 我最开始分析这道题,先了解在二维座标内,成为直线的情况,充分必要条件;因为题目的数据是整数,也比较好分析,常见的情况就是 45 度,90 度,180 度的线条,在这些线条上假如存在连续的点,那么他们的座标值 (x, y) 也即 [1, 1]应该是一个等差数列。如果点是不连续的,或有其他情况,等差有不同的值;类似的有考虑到使用斜率的方法,官方给出的枚举方法,可以解决点不连续的问题,从一个点出发,看是否有其他点在同一条直线上,应用斜率的推导公式。

  • 另外一个前提,平面内任意 2 点都可以画一条直线,问题是在第 3 点起,及之后的点的判断;就是一个 2 重循环的判断,对于列表中任一点 i (xi, yi), 考虑其他点 j (xj, yj) ,i + 2 < j < n-1,编码中是从 i + 1 起,因为要先算出一个斜率来;

  • 使用 hash 表,也即 dict 保存键 i, 值是 count, 在一条线上的点的数量,在循环判断中如果新的点计算斜率相同,count + 1;

  • 这里面有个问题,可能存在重复的线条,所以为了区分每一条线条,应该将斜率作为 hash 表的键,而且其能保证是不重复的线条;要注意的是水平线条不存在斜率,需要单独处理。

请同时参考官方题解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章