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 表的鍵,而且其能保證是不重複的線條;要注意的是水平線條不存在斜率,需要單獨處理。
請同時參考官方題解。