[LeetCode] 281. 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).

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.

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] ].

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.

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:

  • 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.

 

這道題一打開又是圖又是這么長的題目的,看起來感覺應該是一道相當復雜的題,但是做完之后發現也就那么回事,雖然我不會做,是學習的別人的解法。這道求天際線的題目應該算是比較新穎的題,要是非要在之前的題目中找一道類似的題,也就只有 Merge Intervals了吧,但是與那題不同的是,這道題不是求被合並成的空間,而是求輪廓線的一些關鍵的轉折點,這就比較復雜了,通過仔細觀察題目中給的那個例子可以發現,要求的紅點都跟每個小區間的左右區間點有密切的關系,而且進一步發現除了每一個封閉區間的最右邊的結束點是樓的右邊界點,其余的都是左邊界點,而且每個紅點的縱坐標都是當前重合處的最高樓的高度,但是在右邊界的那個樓的就不算了。在網上搜了很多帖子,發現網友Brian Gordon的帖子圖文並茂,什么動畫漸變啊,橫向掃描啊,簡直叼到沒朋友啊,但是叼到極致后就懶的一句一句的去讀了,這里博主還是講解另一位網友百草園的博客吧。這里用到了 multiset 數據結構,其好處在於其中的元素是按堆排好序的,插入新元素進去還是有序的,而且執行刪除元素也可方便的將元素刪掉。這里為了區分左右邊界,將左邊界的高度存為負數,建立左邊界和負高度的 pair,再建立右邊界和高度的 pair,存入數組中,都存進去了以后,給數組按照左邊界排序,這樣就可以按順序來處理那些關鍵的節點了。在 multiset 中放入一個0,這樣在某個沒有和其他建築重疊的右邊界上,就可以將封閉點存入結果 res 中。下面按順序遍歷這些關鍵節點,如果遇到高度為負值的 pair,說明是左邊界,那么將正高度加入 multiset 中,然后取出此時集合中最高的高度,即最后一個數字,然后看是否跟 pre 相同,這里的 pre 是上一個狀態的高度,初始化為0,所以第一個左邊界的高度絕對不為0,所以肯定會存入結果 res 中。接下來如果碰到了一個更高的樓的左邊界的話,新高度存入 multiset 的話會排在最后面,那么此時 cur 取來也跟 pre 不同,可以將新的左邊界點加入結果 res。第三個點遇到綠色建築的左邊界點時,由於其高度低於紅色的樓,所以 cur 取出來還是紅色樓的高度,跟 pre 相同,直接跳過。下面遇到紅色樓的右邊界,此時首先將紅色樓的高度從 multiset 中刪除,那么此時 cur 取出的綠色樓的高度就是最高啦,跟 pre 不同,則可以將紅樓的右邊界橫坐標和綠樓的高度組成 pair 加到結果 res 中,這樣就成功的找到我們需要的拐點啦,后面都是這樣類似的情況。當某個右邊界點沒有跟任何樓重疊的話,刪掉當前的高度,那么 multiset 中就只剩0了,所以跟當前的右邊界橫坐標組成pair就是封閉點啦,具體實現參看代碼如下:

 

class Solution {
public:
    vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
        vector<pair<int, int>> h, res;
        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]});
        }
        sort(h.begin(), h.end());
        m.insert(0);
        for (auto &a : h) {
            if (a.second < 0) m.insert(-a.second);
            else m.erase(m.find(a.second));
            cur = *m.rbegin();
            if (cur != pre) {
                res.push_back({a.first, cur});
                pre = cur;
            }
        }
        return res;
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/281

 

類似題目:

Falling Squares

Rectangle Area II

 

參考資料:

https://leetcode.com/problems/the-skyline-problem/

http://www.cnblogs.com/easonliu/p/4531020.html

https://briangordon.github.io/2014/08/the-skyline-problem.html

https://leetcode.com/problems/the-skyline-problem/discuss/61193/Short-Java-solution

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM