131. The Skyline Problem
中文English
Given N buildings in a x-axis,each building is a rectangle and can be represented by a triple (start, end, height),where start is the start position on x-axis, end is the end position on x-axis and height is the height of the building. Buildings may overlap if you see them from far away,find the outline of them。
An outline can be represented by a triple, (start, end, height), where start is the start position on x-axis of the outline, end is the end position on x-axis and height is the height of the outline.
Example 1
Input:
[
[1, 3, 3],
[2, 4, 4],
[5, 6, 1]
]
Output:
[
[1, 2, 3],
[2, 4, 4],
[5, 6, 1]
]
Explanation:
The buildings are look like this in the picture. The yellow part is buildings.
Example 2
Input:
[
[1, 4, 3],
[6, 9, 5]
]
Output:
[
[1, 4, 3],
[6, 9, 5]
]
Explanation:
The buildings are look like this in the picture. The yellow part is buildings.
Notice
Please merge the adjacent outlines if they have the same height and make sure different outlines cant overlap on x-axis.
解法1:这题不容易。思路参考自网上。注意这题一定只要比较每个building的开始时间,不能把开始时间和结束时间混在一起。
1) 用multiset(相当于最大堆),存储buildings的高度。
2) 遍历buildings,每次当building的起始位置时进堆,结束位置时出堆。
3) 当本次heap的最大值与上次记录heap的最大值不一致(不管是变大还是变小)时,检查上次heap记录的最大值的高度和时间,若都非0,则记录{preTime, curTime, preHeight},同时更新curTime, preHeight, preTime。
4) multiset一定要先插入一个0,不然堆可能为空。
5) buildings排序有讲究:
a) if two time are the same, but different time type, the starting time is ahead of ending time
b) if two time are the same, and are both starting time, then higher building first
c) if two time are the same, and are both ending time, then lower building first
d) if two time are different, smaller time first
class Solution {
public:
/**
* @param buildings: A list of lists of integers
* @return: Find the outline of those buildings
*/
vector<vector<int>> buildingOutline(vector<vector<int>> &buildings) {
vector<pair<int, int>> h, record;
multiset<int> m;
int pre = 0, cur = 0;
for (auto &a : buildings) {
h.push_back({a[0], -a[2]});
h.push_back({a[1], a[2]});
}
//sorting,
//1) if two time are the same, but different time type, the starting time is ahead of ending time
//2) if two time are the same, and are both starting time, then higher building first
//3) if two time are the same, and are both ending time, then lower building first
//4) if two time are different, smaller time first
sort(h.begin(), h.end());
m.insert(0);
for (auto &a : h) {
if (a.second < 0) m.insert(-a.second); //only when it is beginning border, insert the border
else m.erase(m.find(a.second)); //remove the ending border
cur = *m.rbegin(); //the highest one in multiset
if (cur != pre) {
record.push_back({a.first, cur});
pre = cur;
}
}
vector<vector<int>> res;
int n = record.size();
for (int i = 1; i < n; ++i) {
if (record[i - 1].second > 0)
res.push_back({record[i - 1].first, record[i].first, record[i - 1].second});
}
return res;
}
};
解法2:类似解法1,不过还是用中规中矩的Node结构(time, type和height)来做。
代码如下:
struct Node {
int time;
int type; // 1: start, 2: end
int height;
Node(int tm = 0, int tp = 0, int ht = 0) : time(tm), type(tp), height(ht) {}
//sorting,
//1) if two time are the same, but different time type, the starting time is ahead of ending time
//2) if two time are the same, and are both starting time, then higher building first
//3) if two time are the same, and are both ending time, then lower building first
//4) if two time are different, smaller time first
bool operator < (const Node & n) {
if (this->time == n.time) {
if (this->type != n.type) {
return this->type == 1;
} else {
return (this->type == 1) ? this->height >= n.height : this->height < n.height;
}
} else {
return this->time < n.time;
}
}
};
class Solution {
public:
/**
* @param buildings: A list of lists of integers
* @return: Find the outline of those buildings
*/
vector<vector<int>> buildingOutline(vector<vector<int>> &buildings) {
vector<Node> heights;
multiset<int> m;
int preHeight = 0, curHeight = 0;
int preTime = 0, curTime = 0;
vector<vector<int>> res;
for (auto &building : buildings) {
heights.push_back(Node(building[0], 1, building[2]));
heights.push_back(Node(building[1], 2, building[2]));
}
sort(heights.begin(), heights.end());
m.insert(0); // in case multiset is empty
for (auto &height : heights) {
if (height.type == 1) m.insert(height.height); //if starting border, insert the height into multiset
else m.erase(m.find(height.height)); //if ending border, erase one of the height from multiset
curHeight = *m.rbegin(); //the highest height in multiset
//each time if the current highest height in multiset is different from previous highest height, and preTime && preHeight > 0, record the segment.
if (curHeight != preHeight) {
if (preTime != 0 && preHeight != 0) res.push_back({preTime, height.time, preHeight});
curTime = height.time;
preHeight = curHeight;
preTime = curTime;
}
}
return res;
}
};