218. The Skyline Problem solving Report

Description:

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

[
5553912-faf4183967229ed3.png
Buildings

](https://leetcode.com/static/images/problemset/skyline1.jpg)

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

Link:

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

解题方法:

通过观察可以知道,根据水平轴的推移,当前的水平坐标的高度出现变化的时候,我们需要记录下点。
所以,

  1. 首先应该把所有的建筑起始点终止点都记录下来,起始点的高度为正,终止点的高度为负,这样就可以做出区分。
  2. 然后对所有的点进行排序,当处在同一坐标下,高度大的排在前面,否则按照水平坐标从小到大排,这样有一个好处就是:当碰到input是[[0,2,3],[2,5,3]]的时候,第二个(2,3)会排在(2,-3)前面,就避免了相连线段在记录的时候断开的情况。同时,针对input是[[0,2,3],[1,2,1],[2,4,1],[2,5,3]],也会避免我们先接触到比较矮的建筑。
  3. 用一个tree map来记录当前的水平坐标上的高度,当我们碰到一个初始点,如果当前建筑最高的高度都不如这个初始点的高度,记录这个坐标。当我们碰到一个终止点的时候,应该把对应的高度-1,如果这个高度已经没有了,应该把这个高度从tree map中移除。并且,在碰到一个终止点之后,tree map的最高高度有变化,说明之前最高的建筑已经走完了,需要记录下目前坐标和第二高的高度。

Tips:

LeetCode answer this question is problematic:
When the input is [[0,2,3],[2,5,3]]when,

5553912-56634cbbed2b1dd7.png
image.png

Description The default answer two questions at the same height, the building is connected to the same ending.
However , when the input is [[0,2,3],[1,2,1],[2,4,1],[2,5,3]] the time,
5553912-4e12d5ec907b04b2.png
image.png

LeetCode answer and there is a problem.

Time Complexity:

nlogn

Complete code:

class Solution {
public:
    vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
        vector<vector<int>> ans;
        int size = buildings.size();
        if(!size)
            return ans;
        vector<vector<int>> points;
        for(auto building: buildings) {
            points.push_back({building[0], building[2]});
            points.push_back({building[1], -building[2]});
        }
        sort(points.begin(), points.end(), [](vector<int>& a, vector<int>& b){
            if(a[0] < b[0] || (a[0] == b[0] && a[1] > b[1]))
                return true;
            else
                return false;
        });
        map<int, int, greater<int>> heights;
        heights[0] = 1;
        for(auto point: points) {
            if(point[1] > 0) {
                if(point[1] > heights.begin()->first) {
                    ans.push_back({point[0], point[1]});
                }
                heights[point[1]]++;
            } else {
                heights[abs(point[1])]--;
                if(heights[abs(point[1])] == 0) {
                    heights.erase(abs(point[1]));
                }
                if(abs(point[1]) > heights.begin()->first) {
                    ans.push_back({point[0], heights.begin()->first});
                }
            }
        }
        return ans;
    }
};

Guess you like

Origin blog.csdn.net/weixin_34015566/article/details/90989047