题目链接:https://leetcode-cn.com/problems/the-skyline-problem/
题目描述
城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图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], …]
代码
1 从左往右扫描
- 把每栋房子看作矩形,首先把矩形(Li,-Hi)和(Ri,Hi)插入到multiset st中,自动排序
- 遍历multiset st,同时用另一个multiset height保存当前位置左边的历史高度,height.rbegin()即其最大值
- 遍历过程中,如果发现是Li,则插入到height,否则是Ri,删除Ri在height中对应的Li
- 如果height的最大值发生了变化,则该i元素就是返回结果之一
复杂度分析:
时间复杂度O()
class Solution {
public:
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
if (buildings.empty()) return {};
multiset<pair<int, int>> st; // 存储自动排序
// 将矩形左右端点加入
for (auto b : buildings){
st.insert(make_pair(b[0],-b[2]));
st.insert(make_pair(b[1],b[2]));
}
vector<vector<int>> ret;
multiset<int> height = {0};
int m = 0;
// 从左往右扫描
for (auto s:st){
if (s.second < 0) height.insert(-s.second); // 矩形左端点,加入对应高度
else height.erase(height.find(s.second)); // 矩形右端点,删除对应高度
if (m != *height.rbegin()) // 出现关键点
ret.push_back({s.first, *height.rbegin()});
m = *height.rbegin();
}
return ret;
}
};
离散化+线段树
todo