LeetCode-218 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).
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] ]
.
题目大意
如上图所示,给定一组矩形的位置和高度,要求求出这些矩形的轮廓上的转折点的位置。
(PS:转折点为不同高度上的最左边的点的坐标,若两个矩形不相互重叠,则这两个矩形可以有相同高度的转折点,与此同时,在最后应加上高度为0的最靠右的转折点作为闭点)
示例
E1
解题思路
该思路源于LeetCode@liuyifly06,即将每个矩形的左边与右边按照左右顺序保存下来,并用multiset来存储当前的最高的高度为多少。
整个过程是遍历所有矩阵的左右边界的过程,当遍历到某个矩阵的左边界时,将该边界加入到multiset中,由于同一矩形左右边界上的高度一样,当遍历到某个矩阵的右边界时,只需将multiset中的该矩阵的高度删除即可,因为该矩阵的高度一定已被计算过。
我们只需访问multiset的最后一个节点,因为它代表了当前访问到的矩阵当中最高的高度,用两个指针分别保存上一个高度状态和当前的高度状态,来进行判断是否将当前的坐标加入到最终结果中。
复杂度分析
时间复杂度:O(N)
空间复杂度:O(N)
代码
class Solution { public: vector<vector<int>> getSkyline(vector<vector<int>>& buildings) { vector<vector<int> > height, res; multiset<int> line; int pre = 0, cur = 0; //将矩阵的左右边界以及其高度放入数组中,为了区分左右边界,将高度分为正负值 //即可 for(auto &b : buildings) { vector<int> tmp(2, 0); tmp[0] = b[0]; tmp[1] = -b[2]; height.push_back(tmp); tmp[0] = b[1]; tmp[1] = b[2]; height.push_back(tmp); } //将数组按照横坐标进行排序 sort(height.begin(), height.end()); //将0加入multiset,为了能够在遍历的过程中可以得到两个不重叠矩阵的高度为0的 //坐标位置 line.insert(0); //遍历所有的矩阵的边界状态 for(auto &h : height) { //若访问到一个矩阵的左边界,将其加入multiset if(h[1] < 0) line.insert(-h[1]); //若访问到一个矩阵的右边界,代表其已被成功计算加入到最终结果,删除即可 else line.erase(line.find(h[1])); //访问当前的最高矩阵高度 cur = *line.rbegin(); //若与之前的不同,说明新加入的高度为最高高度,将其加入到最终结果当中 if(cur != pre) { res.push_back({h[0], cur}); pre = cur; } } return res; } };