算法課作業系列6——The Skyline Problem

算法設計課作業系列(5)

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

A
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_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.

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.

解題過程

解題思路

其實我們可以類比我們手動去標註輪廓的過程,遵循以下步驟:
1. 將一個矩形看成兩個點,左邊的點表示矩形的開始,右邊點表示矩形的結束
2. 將所有點存入一個數組,並且按照橫座標順序排序放好
3. 遇到左邊的點去判斷這個點的加入是否會導致最高的高度的變化,如果會則輸出這個點的橫座標和高度。其實很好理解,就像你在描邊的時候,一個新的更高的矩形出現了,自然你需要去往上描,而如果下一個矩形要矮一些,那麼也就不會有輪廓上的突出了
4. 遇到右邊點則把對應的左邊點輸出,若整體的最高的高度改變了,則輸出這個點的橫座標以及現在的高度。也很容易理解,因爲如果這個矩形移出之後整體高度改變,那一定會在輪廓上表現出來
在完成以上的過程之後,問題也就基本解決了,當然會有一些測試樣例無法通過,但是隻要對所有點排布的順序稍加改變就可以了,這裏不詳細說明,因爲沒有辦法說那麼細。

源代碼

typedef struct _Point {
    bool type;
    int height;
    int x;
    _Point(bool _type, int _height, int _x): type(_type), height(_height), x(_x) {}
} _Point;

bool comp(_Point& a, _Point& b) {
    if (a.x == b.x) {
        if (a.type && !b.type) {
            return true;
        } else if (b.type && !a.type) {
            return false;
        } else if (a.type && b.type) {
            return a.height > b.height;
        } else {
            return a.height < b.height;
        }
    }
    return a.x < b.x;
}

class Solution {
public:
    vector<pair<int, int> > getSkyline(vector<vector<int> >& buildings) {
        vector<_Point> points;
        for (int i = 0; i < buildings.size(); i++) {
            points.push_back(_Point(true, buildings[i][2], buildings[i][0]));
            points.push_back(_Point(false, buildings[i][2], buildings[i][1]));
        }
        sort(points.begin(), points.end(), comp);
        map<int, int> count;
        vector<pair<int, int> > ret;
        count.insert(make_pair(0, 1));
        int prev = 0;
        for (int i = 0; i < points.size(); i++) {
            if (points[i].type) {
                count[points[i].height]++;
            } else {
                count[points[i].height]--;
                if (count[points[i].height] == 0) {
                    count.erase(points[i].height);
                }
            }
            if (prev != count.rbegin()->first) {
                prev = count.rbegin()->first;
                ret.push_back(make_pair(points[i].x, prev));
            }
        }
        return ret;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章