1.题目描述
城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图A)上显示的所有建筑物的位置和高度,请编写一个程序以输出由这些建筑物形成的天际线(图B)。
每个建筑物的几何信息用三元组 [Li,Ri,Hi] 表示,其中 Li 和 Ri 分别是第 i 座建筑物左右边缘的 x 坐标,Hi 是其高度。可以保证 0 ≤ Li, Ri ≤ INT_MAX, 0 < Hi ≤ INT_MAX 和 Ri - Li > 0。您可以假设所有建筑物都是在绝对平坦且高度为 0 的表面上的完美矩形。
例如,图A中所有建筑物的尺寸记录为:[ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ] 。
输出是以 [ [x1,y1], [x2, y2], [x3, y3], ... ] 格式的“关键点”(图B中的红点)的列表,它们唯一地定义了天际线。关键点是水平线段的左端点。请注意,最右侧建筑物的最后一个关键点仅用于标记天际线的终点,并始终为零高度。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
例如,图B中的天际线应该表示为:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]。
说明:
任何输入列表中的建筑物数量保证在 [0, 10000] 范围内。
输入列表已经按左 x 坐标 Li 进行升序排列。
输出列表必须按 x 位排序。
输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...] 是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]
2.解题思路
其实这道题的关键是:找到转折点(所求),即最大高度变化的点。
使用扫描线,从左至右扫过。如果遇到左端点,将高度入堆,如果遇到右端点,则将高度从堆中删除。使用 last 变量记录上一个转折点。
可以参考下面的图,扫描线下方的方格就是堆。
作者:ivan_allen
链接:https://leetcode-cn.com/problems/the-skyline-problem/solution/218tian-ji-xian-wen-ti-sao-miao-xian-fa-by-ivan_al/
参考在代码中的注释:
public:
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
multiset<pair<int, int>> all;
vector<vector<int>> res;
for (auto& e : buildings) {
all.insert(make_pair(e[0], -e[2])); // critical point, left corner
all.insert(make_pair(e[1], e[2])); // critical point, right corner
}
multiset<int> heights({0}); // 保存当前位置所有高度。
vector<int> last = {0, 0}; // 保存上一个位置的横坐标以及高度
for (auto& p : all) {
if (p.second < 0) heights.insert(-p.second); // 左端点,高度入堆
else heights.erase(heights.find(p.second)); // 右端点,移除高度
// 当前关键点,最大高度
auto maxHeight = *heights.rbegin();
// 当前最大高度如果不同于上一个高度,说明这是一个转折点
if (last[1] != maxHeight) {
// 更新 last,并加入结果集
last[0] = p.first;
last[1] = maxHeight;
res.push_back(last);
}
}
return res;
}
};
3.代码实现
import heapq
class Solution(object):
def getSkyline(self, buildings):
"""
:type buildings: List[List[int]]
:rtype: List[List[int]]
"""
all=sorted([(building[0], -building[2]) for building in buildings]+[(building[1], building[2]) for building in buildings])
res=[]
heights=[0]
heapq.heapify(heights)
last=[0,0]
for p in all:
if p[1] < 0:
heapq.heappush(heights,-p[1])
else:
heights.remove(p[1])
maxHeight = heapq.nlargest(1, heights)
if last[1] != maxHeight[0]:
last=[p[0], maxHeight[0]]
res.append(last)
return res