1. 解题思路
这一题和题目3623. Count Number of Trapezoids I很像,不过难度在于不要求边平行于x轴了,而是任意方向上的梯形都可以。
因此,思路上我们就是首先遍历一下所有的线段,计算出其所处的直线 ( k , b ) (k, b) (k,b),然后我们只需要取斜率 k k k相同,而 b b b不同的任意两条直线,其上的所有线段的乘积即为当前方向上的梯形的个数。
不过,需要注意的是,在这里,如果选取的梯形事实上是一个平行四边形,那么它就会在两个平行方向上各自被count一次,就会导致结果错误,因此我们需要从返回的结果当中减去图中的所有平行四边形的个数。
而如果计算平行四边形的个数,问了一下deepseek之后倒是给出了一个简单的思路,就是计算所有的线段的中点,只要中点相同,那么对应的两条线段就必然可以构成一个平行四边形,除非其恰好共线。
因此,我们使用上述方式减去所有的平行四边形之后,只需要找到所有的共线点,然后考察其可以构成多少个“平行四边形”,然后将对应的数加回去即可。
2. 代码实现
给出python代码实现如下:
class Solution:
def countTrapezoids(self, points: List[List[int]]) -> int:
n = len(points)
def cal_line(i, j):
x1, y1 = points[i]
x2, y2 = points[j]
k = (y1-y2)/(x1-x2) if x1 != x2 else 1e9
b = (x2*y1-x1*y2) / (x1-x2) if x1 != x2 else x1
return (k, b)
edges = defaultdict(lambda: defaultdict(int))
lines = defaultdict(set)
for i in range(n-1):
for j in range(i+1, n):
k, b = cal_line(i, j)
edges[k][b] += 1
lines[(k,b)].add(i)
lines[(k,b)].add(j)
if len(edges) == 1:
return 0
ans = 0
for k, bs in edges.items():
bs = list(bs.values())
m = len(bs)
for i in range(m-1):
n1 = bs[i]
for j in range(i+1, m):
n2 = bs[j]
ans += n1 * n2
def count_parallelograms(points):
n = len(points)
# 哈希表记录每个中点(存储2倍值避免浮点误差)的出现次数
midpoint_count = defaultdict(int)
# 遍历所有点对 (i, j) 其中 i < j
for i in range(n):
x1, y1 = points[i]
for j in range(i + 1, n):
x2, y2 = points[j]
# 计算中点*2(整数存储避免除法)
mx = x1 + x2
my = y1 + y2
midpoint_count[(mx, my)] += 1
# 统计平行四边形总数
total = 0
for count in midpoint_count.values():
if count >= 2:
# 组合公式 C(count, 2) = count*(count-1)//2
total += count * (count - 1) // 2
return total
dup = count_parallelograms(points)
for line in lines.values():
_points = [points[i] for i in line]
if len(_points) >= 4:
dup -= count_parallelograms(_points)
return ans - dup
提交代码评测得到:耗时2392ms,占用内存126.76MB。