[LeetCode] The Skyline Problem

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

Buildings Skyline Contour

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_MAX0 < 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

  • The number of buildings in any input list is guaranteed to be in the range [0, 10000].
  • The input list is already sorted in ascending order by the left x position Li.
  • The output list must be sorted by the x position.
  • There must be no consecutive horizontal lines of equal height in the output skyline. For instance, [...[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上也有一道跟這道同樣,不過只是輸出的結果不一樣。

http://www.lintcode.com/en/problem/building-outline/

相關文章
相關標籤/搜索