题目
给定一个二维平面,平面上有 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
方案一
from fractions import Fraction
class Solution:
def maxPoints(self, points: List[List[int]]) -> int:
'''ax+b=y
对于点(x1, y1),(x2, y2)
a = (y2 - y1) / (x2 - x1)
b = y1 - ax1
'''
if len(points) == 1:
return 1
res = 0
for i in range(len(points)):
duplicate = 1 # 重复点的个数
slope = {} # key: (y2 - y1) / (x2 - x1), value: int, 斜率相同的点的个数
for j in range(i + 1, len(points)):
x1, y1 = points[i]
x2, y2 = points[j]
if x1 == x2 and y1 == y2: # 重复点的个数
duplicate += 1
continue
if x1 - x2 == 0: # 垂直线
if float('inf') not in slope:
slope[float('inf')] = 0
slope[float('inf')] += 1
elif y1 - y2 == 0: # 水平线
if 0 not in slope:
slope[0] = 0
slope[0] += 1
else:
slope_ = Fraction(y2 - y1, x2 - x1) # 防止精度问题,此处应又更好的解决方案
if slope_ not in slope:
slope[slope_] = 0
slope[slope_] += 1
l = [v for v in slope.values()]
res = max(res, max(l) + duplicate) if l else max(res, duplicate)
return res
- 双重遍历,在遍历的同时统计经过该点且斜率相同的点的个数,然后加上重复点的个数即是目标值
注意水平线和垂直线的处理。
leetcode 解答(方案相同,效率却极好)
class Solution:
def maxPoints(self, points: List[List[int]]) -> int:
cnt = collections.Counter((x, y) for x, y in points)
if len(cnt) <= 2:
return len(points)
ans = 0
for _ in range(1, len(cnt)):
(x1, y1), t1 = cnt.popitem()
slp = collections.defaultdict(lambda: t1)
for (x2, y2), t2 in cnt.items():
s = (y2 - y1) / (x2 - x1) if x1 != x2 else float('Inf')
slp[s] += t2
ans = max(ans, max(slp.values()))
return ans
- 怎么解决精度问题的???——没有解决精度问题,测试通过是因为
cnt
每次popitem
的时候不会先弹出来(0, 0)
这个点。具体请debug这个测试用例。points = [[0, 0], [94911151, 94911150], [94911152, 94911151]]
如果popitem
第一次弹出(0, 0)
则会出bug
原文
https://leetcode-cn.com/explore/orignial/card/all-about-lockup-table/239/learn-to-use-keys/1003/