题目描述
城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图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], ...]
问题分析
这对我来说是一道难题,看了别人的代码才搞懂。先将数组buildings中各个楼的左顶点和右顶点保存到数组high中,这里将每个楼的左顶点的高度在数组high中记录成负值,这样既保存了高度信息,又记录了是左顶点。然后将各个顶点排序,调用sort可直接按照从左到右的位置排序。接下来我们从左到右遍历这个数组high,如果当前顶点的高度小于0,那么说明这是左顶点,我们把它的高度存入multiset中;否则说明这是右顶点,我们要从multiset中把该顶点的高度去掉。接下来我们取得multiset中的最大值记为cur,如果cur不等于pre,说明此时遇到了一个记录点,我们将该点保存在数组ans中,然后将pre更新为cur。如此循环直到数组high遍历结束,那么也就得到结果ans了,返回即可。
代码实现
class Solution {
public:
vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
vector<pair<int, int>> high, ans;
multiset<int> m;
for(auto& a : buildings){
high.push_back({a[0], -a[2]});
high.push_back({a[1], a[2]});
}
int pre = 0, cur = 0;
sort(high.begin(), high.end());
m.insert(0);
for(auto& a : high){
if(a.second < 0)
m.insert(-a.second);
else
m.erase(m.find(a.second));
cur = *m.rbegin();
if(cur != pre){
ans.push_back({a.first, cur});
pre = cur;
}
}
return ans;
}
};