扫描线(Sweep Line)算法。从左到右遍历每个出现过的坐标(不管是作为building起始还是结束)。
关键思想是:
- 永远维护一个
[cur_s, x)
的平均高度before
(初始时假设为None
) - 处理坐标x处的所有出点和入点(顺序无关),得到处理之后的平均高度
after
- 如果处理之后,平均高度发生了变化,那么就把
[cur_s, x, before]
加进去
实现扫描线可以用哈希数组或者堆。
heap
from heapq import heappush, heappop
class Solution:
def averageHeightOfBuildings(self, buildings: List[List[int]]) -> List[List[int]]:
pts = []
for s, e, h in buildings:
heappush(pts, (s, h))
heappush(pts, (e, -h))
total, cnt, prev = 0, 0, None
cur_s = None
ans = []
while pts:
x = pts[0][0]
while pts and pts[0][0] == x:
_, h = heappop(pts)
total += h
cnt += -1 if h < 0 else 1
avg = total // cnt if cnt > 0 else None
if avg != prev:
if prev is not None:
ans.append([cur_s, x, prev])
cur_s = x
prev = avg
return ans
- 添加点: O ( N l o g N ) O(NlogN) O(NlogN)
- 取出点: O ( N l o g N ) O(NlogN) O(NlogN)
哈希数组
from heapq import heappush, heappop
from collections import defaultdict
class Solution:
def averageHeightOfBuildings(self, buildings: List[List[int]]) -> List[List[int]]:
total, cnt = defaultdict(int), defaultdict(int)
for s, e, h in buildings:
total[s] += h
cnt[s] += 1
total[e] -= h
cnt[e] -= 1
t, c, prev_avg = 0, 0, None
cur_s = None
ans = []
for x in sorted(total.keys()):
t += total[x]
c += cnt[x]
avg = t // c if c > 0 else None
if prev_avg != avg:
if prev_avg is not None:
ans.append([cur_s, x, prev_avg])
cur_s = x
prev_avg = avg
return ans
- 统计坐标的变化值: O ( N ) O(N) O(N)
- 排序: O ( H l o g H ) O(HlogH) O(HlogH),H是出现过的所有不同坐标的个数,H<=2N
- 从左到右扫描: O ( H ) O(H) O(H)
总得来说,堆<=哈希数组的