A city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Now suppose you are given the locations and height of all the buildings as shown on a cityscape photo (Figure A), write a program to output the skyline formed by these buildings collectively (Figure B).node
The geometric information of each building is represented by a triplet of integers [Li, Ri, Hi]
, where Li
and Ri
are the x coordinates of the left and right edge of the ith building, respectively, and Hi
is its height. It is guaranteed that 0 ≤ Li, Ri ≤ INT_MAX
, 0 < Hi ≤ INT_MAX
, and Ri - Li > 0
. You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.ide
For instance, the dimensions of all buildings in Figure A are recorded as: [ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ]
.ui
The output is a list of "key points" (red dots in Figure B) in the format of [ [x1,y1], [x2, y2], [x3, y3], ... ]
that uniquely defines a skyline. A key point is the left endpoint of a horizontal line segment. Note that the last key point, where the rightmost building ends, is merely used to mark the termination of the skyline, and always has zero height. Also, the ground in between any two adjacent buildings should be considered part of the skyline contour.this
For instance, the skyline in Figure B should be represented as:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]
.编码
Notes:spa
[0, 10000]
.Li
.[...[2 3], [4 5], [7 5], [11 5], [12 7]...]
is not acceptable; the three lines of height 5 should be merged into one in the final output as such: [...[2 3], [4 5], [12 7], ...]
Credits:
Special thanks to @stellari for adding this problem, creating these two awesome images and all test cases.code
https://leetcode.com/problems/the-skyline-problem/orm
分别将每一个线段的左边节点与右边节点存到新的vector height中,根据x坐标值排序,而后遍历求拐点。求拐点的时候用一个最大化heap来保存当前的楼顶高度,遇到左边节点,就在heap中插入高度信息,遇到右边节点就从heap中删除高度。分别用pre与cur来表示以前的高度与当前的高度,当cur != pre的时候说明出现了拐点。在从heap中删除元素时要注意,我使用priority_queue来实现,priority_queue并不提供删除的操做,因此又用了别外一个unordered_map来标记要删除的元素。在从heap中pop的时候先看有没有被标记过,若是标记过,就一直pop直到空或都找到没被标记过的值。别外在排序的时候要注意,若是两个节点的x坐标相同,咱们就要考虑节点的其它属性来排序以免出现冗余的答案。且体的规则就是若是都是左节点,就按y坐标从大到小排,若是都是右节点,按y坐标从小到大排,一个左节点一个右节点,就让左节点在前。下面是AC的代码。htm
1 class Solution { 2 private: 3 enum NODE_TYPE {LEFT, RIGHT}; 4 struct node { 5 int x, y; 6 NODE_TYPE type; 7 node(int _x, int _y, NODE_TYPE _type) : x(_x), y(_y), type(_type) {} 8 }; 9 10 public: 11 vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) { 12 vector<node> height; 13 for (auto &b : buildings) { 14 height.push_back(node(b[0], b[2], LEFT)); 15 height.push_back(node(b[1], b[2], RIGHT)); 16 } 17 sort(height.begin(), height.end(), [](const node &a, const node &b) { 18 if (a.x != b.x) return a.x < b.x; 19 else if (a.type == LEFT && b.type == LEFT) return a.y > b.y; 20 else if (a.type == RIGHT && b.type == RIGHT) return a.y < b.y; 21 else return a.type == LEFT; 22 }); 23 24 priority_queue<int> heap; 25 unordered_map<int, int> mp; 26 heap.push(0); 27 vector<pair<int, int>> res; 28 int pre = 0, cur = 0; 29 for (auto &h : height) { 30 if (h.type == LEFT) { 31 heap.push(h.y); 32 } else { 33 ++mp[h.y]; 34 while (!heap.empty() && mp[heap.top()] > 0) { 35 --mp[heap.top()]; 36 heap.pop(); 37 } 38 } 39 cur = heap.top(); 40 if (cur != pre) { 41 res.push_back({h.x, cur}); 42 pre = cur; 43 } 44 } 45 return res; 46 } 47 };
使用一些技巧能够大大减小编码的复杂度,priority_queue并无提供erase操做,可是multiset提供了,并且multiset内的数据是按BST排好序的。在区分左右节点时,我以前本身建了一个结构体,用一个属性type来标记。这里能够用一个小技巧,那就是把左边节点的高度值设成负数,右边节点的高度值是正数,这样咱们就不用额外的属性,直接用pair<int, int>就能够保存了。并且对其排序,发现pair默认的排序规则就已经知足要求了。blog
1 class Solution { 2 public: 3 vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) { 4 vector<pair<int, int>> height; 5 for (auto &b : buildings) { 6 height.push_back({b[0], -b[2]}); 7 height.push_back({b[1], b[2]}); 8 } 9 sort(height.begin(), height.end()); 10 multiset<int> heap; 11 heap.insert(0); 12 vector<pair<int, int>> res; 13 int pre = 0, cur = 0; 14 for (auto &h : height) { 15 if (h.second < 0) { 16 heap.insert(-h.second); 17 } else { 18 heap.erase(heap.find(h.second)); 19 } 20 cur = *heap.rbegin(); 21 if (cur != pre) { 22 res.push_back({h.first, cur}); 23 pre = cur; 24 } 25 } 26 return res; 27 } 28 };
LintCode上也有一道跟这道同样,不过只是输出的结果不一样。