Tushar: https://www.youtube.com/watch?v=GSBLe8cKu0s
思路:
- sort buildingPoints,用(x, h, isStart) 来记录
- 按 key = height 用TreeMap来实现event heap,因为Java priority queue的insert 和look up时间是O(logn), 但delete时间更长。Java TreeMap可以做到所有都在O(logn)内。c++ multiset都是O(logn)。
- heap 记录了当前的所有“active height”,堆顶是当前的最高点
- corner events 的处理:
3.1. 当(x, h1, isStart), (x, h2, isStart),h1 <= h2 也就是两座楼起点一样,要先加 h2
3.2. 当(x, h1, isEnd), (x, h2, isEnd), h1 <= h2也就是两座楼结束一样,要先删除 h1
3.3. 当(x, h1, isEnd), (x, h2, isStart),同一点一座结束一座开始,要先加入h2
这些特殊顺序的处理都由sorting buildingPoints时定义comparator来完成 - 需要记录的事件包括
4.1. 一座楼开始,且其高度大于current_max, 新楼(x, h)需要记录
4.2. 一座楼开始,其高度已经在heap当中,对应的计数++
4.2. 一座楼结束,且其离开导致current_max被改变,也就是堆顶的entry消失,下一个堆顶的(x, h) 需要记录
但是如果用c++中的multiset,既然允许duplicate key,不需要用TreeMap 进行计数了。只需要每次在入set之前先peek一下之前的最高点prev_max,点推进之后再看一下current_max,如果不一致肯定需要记录接下来(x, current_max)。
知识点:
- 用到了multiset,https://www.geeksforgeeks.org/difference-set-multiset-unordered_set-unordered_multiset/ 这里讲了set, unordered_set, multiset, unordered_multiset的区别。(但是为什么不用priority_queue? 像692一样自定义comparator,extract_max还更快, 也support duplicates https://www.geeksforgeeks.org/does-stl-priority-queue-allow-duplicate-values/)
- int prev_max = *active.rbegin(); 用指针提取最大值
- active.erase(active.find(event.second)); 这里只会删掉一个值,如果有重复并不会多项一起删除。这里如果multiset本身储存着复合structure并且存的时候带有自己的comparator的话,删除的会是排序里重复值的最后一个(332. reconstruct itinerary)
multiset::find:Notice that this function returns an iterator to a single element (of the possibly multiple equivalent elements). To obtain the entire range of equivalent elements, see multiset::equal_range.
需要的数据结构有:
- Point {x_cor, height, isStart}
- vector<Point> buildingPoints
- vector<pair<int, int >> result
- multiset<int> active
方法1:
下次implement一下
方法2:
grandyang:http://www.cnblogs.com/grandyang/p/4534586.html
简化一下数据结构,压缩成2-d向量,就不用建Point了。将isStart这个boolean存储到height的符号当中。
易错点:
- 先要推入一个地平线来保证最低点
class Solution {
public:
vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
if (buildings.size() == 0) return {};
vector<pair<int, int>> buildingPoints, result;
multiset<int> active;
for (auto a : buildings){
// start
buildingPoints.push_back({a[0], -a[2]});
// end
buildingPoints.push_back({a[1], a[2]});
}
// sort是关键
sort(buildingPoints.begin(), buildingPoints.end());
// 先推进一个地平线点,保证最低点
active.insert(0);
int prev_max = 0;
for (auto event: buildingPoints){
// 如果是个起点
if (event.second < 0){
active.insert(-event.second);
}
// 如果是个终点
else {
active.erase(active.find(event.second));
}
int current_max = *active.rbegin();
if (prev_max != current_max) {
result.push_back({event.first, current_max});
prev_max = current_max;
}
}
return result;
}
};
二刷:
class Solution {
public:
vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
auto cmp = [](pair<int, int> & a, pair<int, int> & b) {
if (a.first == b.first) {
if (!(a.second > 0 ^ b.second > 0)) {
return a.second < b.second;
}
return a.second < 0;
}
return a.first > b.first;
};
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> pq(cmp);
for (auto b: buildings) {
pq.push({b[0], b[2]});
pq.push({b[1], -b[2]});
}
vector<vector<int>> res;
multiset<int> active;
active.insert(0);
while (!pq.empty()) {
auto top = pq.top();
pq.pop();
int pos = top.first;
int height = abs(top.second);
bool start = top.second > 0;
if (start) {
if (*active.rbegin() < height) {
res.push_back({pos, height});
}
active.insert(height);
}
else {
active.erase(active.find(height));
if (*active.rbegin() < height) {
res.push_back({pos, *active.rbegin()});
}
}
}
return res;
}
};