[H扫描线] lc218. 天际线问题(扫描线求轮廓+边界情况+好题+算法技巧)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[H扫描线] lc218. 天际线问题(扫描线求轮廓+边界情况+好题+算法技巧)相关的知识,希望对你有一定的参考价值。
1. 题目来源
链接:218. 天际线问题
题解:
2. 题目解析
有点难。
扫描线问题,还是一个求轮廓的扫描线问题…故不需要线段树维护区间查询(求周长、面积时hi使用线段树)。
从左向右扫,找到每个区间段中的高度最高的线段即可。可参考三叶姐的图:【宫水三叶】扫描线算法基本思路 & 优先队列维护当前最大高度。
由于本题细节很多,代码很精巧。需要讨论的边界情况很多,才能将几个不同的情况采用相同的处理方式,所以单看代码而言,一种操作的背后其实对应了多种情况,都是需要具体情况具体分析的。请参考:T-SHLoRk 题解:LeetCode 218. The Skyline Problem。
关注矩形上边上的两个点,称为该线段的入点、出点,也是扫描线问题的基础。
如果扫描线扫到入点,说明该矩形进入扫描线区间中,如果扫到出点,说明该矩形就要从扫描线区间中出去了。
需要从扫描线维护的区间中找到高度最高的线段作为顶部轮廓线,将左端点 ( x , y ) (x,y) (x,y)加入答案中即可。
需要维护每个顶部轮廓的高度,并且支持排序、插入、删除指定高度。由于本题需要删除指定高度,所以不能使用优先队列来维护高度,但可以使用 multiset
来维护,删除时要使用 find(x)
,而不能直接用 x
。
以 x
下标来排序,顺序扫描每个点,就相当于用 x=k
的直线来扫描每个矩形,multiset
维护顶部轮廓的高度。
- 遇见左端点,即入点时,如果它的高度是大于所有已有高度的,说明来了个最高的矩形,该点和该高度加入答案,再将这个矩形高度加入
multiset
中。 - 遇见右端点,即出点时,说明这个矩形要从扫描线中删除,
multiset
首先将这个矩形的高度删除,在相同的x
点处,可能有相同的出点,甚至有入点,以及与其高度相同的出点、入点等。
建议看题解:T-SHLoRk 题解:LeetCode 218. The Skyline Problem,本题好恶心啊,不想往后分析了。
自己研究的这个数据有点意思:[[0,2,1],[0,1,2],[0,1,3]],包含了入点相同,出点相同,两个情况:
- 相同位置的进点,枚举顺序应先枚举最高的进点。当进点向内进的时候,从高往低进,如果大于当前的最高点,那么就加入答案,否则从低往高进,进一个加一个出错。
- 相同位置的出点,枚举顺序应先枚举最低位置的出点。 当出点
x=1
外出的时候,从低往高出,只有最高点出去后,最高点下面的那个保留的最低点才被加入答案中。 - 出点位置刚好有入点的话,先枚举入点再枚举出点。否则出点先出,答案会加入一个比当前位置更低的入点,显然错误。
建议复看的时候多看几遍吧,相同位置的三种情况分析:
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
空间复杂度:
O
(
n
)
O(n)
O(n)
情况很多,代码很精巧:
class Solution {
public:
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
vector<vector<int>> res;
vector<pair<int, int>> points;
multiset<int> height;
for (auto &b : buildings) {
points.push_back({b[0], -b[2]}); // 左端点,入点。同高度入点从高到低排
points.push_back({b[1], b[2]}); // 右端点,出点。同高度出点从低到高
}
sort(points.begin(), points.end());
height.insert(0); // 加入 x 轴这个高度,因为最后落点会落到 x 轴
for (auto &p : points) {
int x = p.first, h = abs(p.second);
if (p.second < 0) { // 左端点,入点
if (h > *height.rbegin()) res.push_back({x, h}); // 高度最高,加入答案,反向迭代器
height.insert(h);
} else { // 右端点,出点
height.erase(height.find(h)); // 删去该线段高度
if (h > *height.rbegin()) res.push_back({x, *height.rbegin()}); // 删掉后的最高一条线段加入答案
}
}
return res;
}
};
以上是关于[H扫描线] lc218. 天际线问题(扫描线求轮廓+边界情况+好题+算法技巧)的主要内容,如果未能解决你的问题,请参考以下文章