Skip to main content

218.天际线问题

标签: divide-and-conquer, heap

难度: Hard

通过率: 43.36%

原题链接: https://leetcode.com/problems/the-skyline-problem/description/

题目描述

给定一个城市中所有建筑的位置信息和高度,返回由这些建筑共同形成的天际线。每个建筑信息给定为一个数组 buildings,其中 buildings[i] = [lefti, righti, heighti] 。

解题思路

对于此问题,我们可以使用分治法和最大堆来解决。其基本思路是:

  1. 收集所有关键点。在所有建筑物中收集建筑物的开头和结束的关键点,并且记录是开始还是结束。
  2. 对所有关键点按照 x 坐标进行排序。对于相同的 x 值,如果是开始关键点,按高度降序排列;如果是结束关键点,按高度升序排列。
  3. 使用最大堆动态地维护活跃的建筑物高度。对于每一个关键点:
    • 如果是建筑物开始,则加入堆中。
    • 如果是建筑物结束,从堆中移除该建筑物。
  4. 对于每一个关键点,检查当前最大高度是否与上一个最大高度不同,如果不同,说明这是一个新的轮廓关键点,应将其加入到结果中。

通过这种方法,我们可以有效地检测建筑物轮廓线的变换,并最终返回完整的天际线轮廓。

代码实现

import heapq

def getSkyline(buildings):
# 建立事件列表,包括起始和结束事件
events = [(L, -H, R) for L, R, H in buildings]
# 结束事件
events += [(R, 0, None) for _, R, _ in buildings]
# 按照 (x, 高度) 排序,如果 x 相同,起始的高度负数排在前面
events.sort()

# 优先队列/最大堆,使用负数表示最大堆效果
result = [[0, 0]]
liveHeap = [(0, float('inf'))]

for x, negH, R in events:
# 移除已过期的建筑物
while liveHeap[0][1] <= x:
heapq.heappop(liveHeap)
if negH:
# 把新的建筑物加入堆中
heapq.heappush(liveHeap, (negH, R))
# 查询当前最大高度
maxH = -liveHeap[0][0]
# 如果最高点不变,不需要加入结果集
if result[-1][1] != maxH:
result.append([x, maxH])
return result[1:]

复杂度分析

时间复杂度: O(nlogn)O(n \log n),其中 nn 是建筑物的数量。我们需要对所有事件进行排序,并使用堆来管理当前的建筑物。

空间复杂度: O(n)O(n),用于存储堆和最终结果。