算法课作业系列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;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章