欢迎访问LeetCode题解合集
题目描述
城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回由这些建筑物形成的 天际线 。
每个建筑物的几何信息由数组 buildings
表示,其中三元组 buildings[i] = [lefti, righti, heighti]
表示:
-
lefti
是第i
座建筑物左边缘的x
坐标。 -
righti
是第i
座建筑物右边缘的x
坐标。 -
heighti
是第i
座建筑物的高度。
天际线 应该表示为由 “关键点” 组成的列表,格式 [[x1,y1],[x2,y2],...]
,并按x 坐标 进行 排序 。关键点是水平线段的左端点。列表中最后一个点是最右侧建筑物的终点,y
坐标始终为 0
,仅用于标记天际线的终点。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
注意:输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...]
是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]
示例 1:
[HTML_REMOVED]
[HTML_REMOVED]
输入:buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
输出:[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
解释:
图 A 显示输入的所有建筑物的位置和高度,
图 B 显示由这些建筑物形成的天际线。图 B 中的红点表示输出列表中的关键点。
示例 2:
输入:buildings = [[0,2,3],[2,5,3]]
输出:[[0,3],[5,0]]
提示:
-
1 <= buildings.length <= 10^4
-
0 <= lefti < righti <= 2^31 - 1
-
1 <= heighti <= 2^31 - 1
-
buildings
按lefti
非递减排序
题解:
扫描线。
这题关键点是:高度发生变化时,会产生关键点。具体来说:建筑物左边高度升高时,会产生关键点;右边高度降低时,会产生关键点。
我们将建筑物拆分成两部分,记为 {l, -h}
和 {r, h}
,然后将拆分后的建筑物按照以下规则排序:
- 若坐标相等,按照高度从小到大排序;
- 若坐标不等,按照坐标从小到大排序;
这样排序是因为:如果位置都不相等,左边高度变高时,肯定产生关键点,而右边高度降低时,也会产生关键点。而在位置相等的地方,左边最高的是关键点,右边最低的是关键点,从而在第一次遍历到时就会记录结果。
从左往右遍历拆分后的数组,使用 multiset
记录高度值(很关键),遇到左边部分直接插入 multiset
中,并且当前高度比 multiset
最大高度大时,出现关键点,记录结果;遇到右边部分从 multiset
中删除,并且当前高度比 multiset
最大高度大时,出现关键点,记录结果。
时间复杂度:$O(nlogn)$
额外空间复杂度:$O(n)$
class Solution {
using PII = pair<int, int>;
public:
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
int n = buildings.size();
vector<PII> build;
for ( int i = 0; i < n; ++i ) {
build.push_back( {buildings[i][0], -buildings[i][2]} );
build.push_back( {buildings[i][1], buildings[i][2]} );
}
sort( build.begin(), build.end() );
multiset<int> height;
height.insert( 0 );
vector<vector<int>> ret;
for ( auto& it : build ) {
if ( it.second < 0 ) {
if ( -it.second > *height.rbegin() )
ret.push_back( {it.first, -it.second} );
height.insert( -it.second );
} else {
height.erase( height.find(it.second) );
if ( it.second > *height.rbegin() )
ret.push_back( {it.first, *height.rbegin()} );
}
}
return ret;
}
};
/*
时间:32ms,击败:89.09%
内存:14.4MB,击败:78.31%
*/
当然,也可以记录上一个转折点,稍微优化一下:
class Solution {
using PII = pair<int, int>;
public:
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
int n = buildings.size();
vector<PII> build;
for ( int i = 0; i < n; ++i ) {
build.push_back( {buildings[i][0], -buildings[i][2]} );
build.push_back( {buildings[i][1], buildings[i][2]} );
}
sort( build.begin(), build.end() );
multiset<int> height;
height.insert( 0 );
vector<vector<int>> ret;
int pre = 0, now;
for ( auto& it : build ) {
if ( it.second < 0 ) height.insert( -it.second );
else height.erase( height.find(it.second) );
now = *height.rbegin();
if ( now != pre ) {
ret.push_back( {it.first, now} );
pre = now;
}
}
return ret;
}
};
/*
时间:24ms,击败:99.03%
内存:14.4MB,击败:78.06%
*/
博主 为什么要使用multset存高度呀
搞明白了