城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图A)上显示的所有建筑物的位置和高度,请编写一个程序以输出由这些建筑物形成的天际线(图B)
个建筑物的几何信息用三元组[Li,Ri,Hi]表示,其中Li和Ri分别是第 i 座建筑物左右边缘的 x 坐标,Hi 是其高度。可以保证0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX和Ri - Li > 0。您可以假设所有建筑物都是在绝对平坦且高度为 0 的表面上的完美矩形。
思路
先验知识-堆排序
## 调整大顶堆
# 在已经是堆的情况下进行调整
# i :当前需要调整的节点
# n:还没有排序的节点
def adjst_peap(lists,i,n):
l = 2*i+1
r = 2 *i+2
largest = i
if l < n and lists[i]<lists[l]:
largest = l
if r<n and lists[i]<lists[r]:
largest = r
if largest !=i:
lists[i],lists[largest]=lists[largest],lists[i]
# 更新largest的子树
adjst_peap(lists,largest,n)
## 排序
def sort_peap(lists):
n = len(lists)
# build a maxheap
for i in range(n,-1,-1):
adjst_peap(lists,i,n)
# 一个个交换元素
for i in range(n-1,0,-1):
lists[0],lists[i]=lists[i],lists[0]
adjst_peap(lists,0,i)
return lists
lists = [50,45,40,20,25,35,30,10,15]
print(sort_peap(lists))
处理buildings
- 维护一个最小堆,记录当前位置下所有的building
- 将所有的高度取一个反,最小堆的堆顶永远记录着当前位置的最大高度。
- 将所有的building进行排序,左端点从小到大,高度的负数也从小到大,右端点也从小到大
- 在上面的所有点坐标的基础上,为每一个building 添加结束坐标 (R,0,0) 表示这个building在这里就结束了。
- 遍历所有点:
- 维护一个堆,存放对当前和后面天际线有用的坐标点
- 每次循环开始,根据当前已到位置,将堆中没有用的点弹出
- 每次循环,都将当前building的位置加入最小堆
- 如果最小堆的堆顶坐标高度发生改变,则坐标和高度都记录下来。
from heapq import heappush,heappop
class Solution(object):
def getSkyline(self, buildings):
"""
:type buildings: List[List[int]]
:rtype: List[List[int]]
"""
## 重新保存一下building,left从小到大排列,height 从大到小排列,right 从小到大排序
# 记录所有可能发生变化的坐标点
points=[(L,-H,R) for L,R,H in buildings]
points+=[(R,0,0 )for L,R,H in buildings]
points.sort()
## reslut 保存结果
reslut = [(0,0)]
## alive 保存对当前以及后续标注天际线有影响的building
## 第一个表示高度,第二个表示building的右边界
## alive 作为栈顶表示当前位置高度最高的点
alive =[(0,float("inf"))]
for pos,hight,R in points:
while alive[0][1]<=pos:
# 将不会影响后面天际线的building弹出
# alive 是最小堆的根节点
heappop(alive)
if hight:
# 将新加入的building加入堆中
heappush(alive,(hight,R))
if reslut[-1][1]!=-alive[0][0]:
reslut+=[[pos,-alive[0][0]]]
return reslut[1:]