📅  最后修改于: 2023-12-03 15:07:04.710000             🧑  作者: Mango
给定平面上的 $n$ 个点,求其中共线的三元组 $(i, j, k)$ 的数量,满足 $1 \leq i < j < k \leq n$。
该问题可以通过枚举所有可能的三元组 $(i, j, k)$ 并判断它们是否共线,但这样计算的时间复杂度为 $O(n^3)$,无法通过本题。
可以考虑一种更有效的方法。我们首先枚举所有的点对 $(i, j)$,并计算出它们的斜率 $k_{ij}$。对于每一个斜率,我们可以记录对应的点 $i$ 和 $j$ 的个数 $cnt_{ij}$。注意到斜率不存在或者两个点在 $x$ 轴上的情况,需要特殊处理。
然后,对于每一个点 $k$,我们枚举所有与点 $k$ 组成的点对 $(i, j)$,并根据它们的斜率是否与点 $k$ 和 $(i, j)$ 的斜率相同,来判断是否有共线三元组。具体来说,设点 $i$ 和点 $j$ 在点 $k$ 的斜率为 $k_{ik}$ 和 $k_{jk}$,则点 $i,j,k$ 共线当且仅当 $k_{ik}=k_{jk}=k_{ij}$。注意到同一个点 $k$ 可能会被多个点对所包含,所以需要乘上对应的 $cnt_{ij}$。
时间复杂度为 $O(n^2)$。由于点对数量为 $O(n^2)$,所以空间复杂度为 $O(n^2)$。
def count_collinear(n: int, points: List[Tuple[int, int]]) -> int:
cnt = defaultdict(int)
for i in range(n):
for j in range(i + 1, n):
if points[j][0] == points[i][0]:
slope = float('inf')
else:
slope = (points[j][1] - points[i][1]) / (points[j][0] - points[i][0])
cnt[(slope, points[i][0], points[j][0])] += 1
ans = 0
for k in range(n):
for i in range(k):
if points[i][0] == points[k][0]:
slope1 = float('inf')
else:
slope1 = (points[i][1] - points[k][1]) / (points[i][0] - points[k][0])
for j in range(i + 1, k):
if points[j][0] == points[k][0]:
slope2 = float('inf')
else:
slope2 = (points[j][1] - points[k][1]) / (points[j][0] - points[k][0])
ans += cnt[(slope1, points[k][0], points[i][0])] * cnt[(slope2, points[k][0], points[j][0])]
ans += cnt[(slope1, points[k][0], points[j][0])] * cnt[(slope2, points[k][0], points[i][0])]
return ans