[LeetCode] 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] ].
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.
https://leetcode.com/problems/the-skyline-problem/
分别将每个线段的左边节点与右边节点存到新的vector height中,根据x坐标值排序,然后遍历求拐点。求拐点的时候用一个最大化heap来保存当前的楼顶高度,遇到左边节点,就在heap中插入高度信息,遇到右边节点就从heap中删除高度。分别用pre与cur来表示之前的高度与当前的高度,当cur != pre的时候说明出现了拐点。在从heap中删除元素时要注意,我使用priority_queue来实现,priority_queue并不提供删除的操作,所以又用了别外一个unordered_map来标记要删除的元素。在从heap中pop的时候先看有没有被标记过,如果标记过,就一直pop直到空或都找到没被标记过的值。别外在排序的时候要注意,如果两个节点的x坐标相同,我们就要考虑节点的其它属性来排序以避免出现冗余的答案。且体的规则就是如果都是左节点,就按y坐标从大到小排,如果都是右节点,按y坐标从小到大排,一个左节点一个右节点,就让左节点在前。下面是AC的代码。
class Solution {
private:
enum NODE_TYPE {LEFT, RIGHT};
struct node {
int x, y;
NODE_TYPE type;
node(int _x, int _y, NODE_TYPE _type) : x(_x), y(_y), type(_type) {}
};
public:
vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
vector<node> height;
for (auto &b : buildings) {
height.push_back(node(b[], b[], LEFT));
height.push_back(node(b[], b[], RIGHT));
}
sort(height.begin(), height.end(), [](const node &a, const node &b) {
if (a.x != b.x) return a.x < b.x;
else if (a.type == LEFT && b.type == LEFT) return a.y > b.y;
else if (a.type == RIGHT && b.type == RIGHT) return a.y < b.y;
else return a.type == LEFT;
});
priority_queue<int> heap;
unordered_map<int, int> mp;
heap.push();
vector<pair<int, int>> res;
int pre = 0, cur = ;
for (auto &h : height) {
if (h.type == LEFT) {
heap.push(h.y);
} else {
++mp[h.y];
while (!heap.empty() && mp[heap.top()] > ) {
--mp[heap.top()];
heap.pop();
}
}
cur = heap.top();
if (cur != pre) {
res.push_back({h.x, cur});
pre = cur;
}
}
return res;
}
};
使用一些技巧可以大大减少编码的复杂度,priority_queue并没有提供erase操作,但是multiset提供了,而且multiset内的数据是按BST排好序的。在区分左右节点时,我之前自己建了一个结构体,用一个属性type来标记。这里可以用一个小技巧,那就是把左边节点的高度值设成负数,右边节点的高度值是正数,这样我们就不用额外的属性,直接用pair<int, int>就可以保存了。而且对其排序,发现pair默认的排序规则就已经满足要求了。
class Solution {
public:
vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
vector<pair<int, int>> height;
for (auto &b : buildings) {
height.push_back({b[], -b[]});
height.push_back({b[], b[]});
}
sort(height.begin(), height.end());
multiset<int> heap;
heap.insert();
vector<pair<int, int>> res;
int pre = , cur = ;
for (auto &h : height) {
if (h.second < ) {
heap.insert(-h.second);
} else {
heap.erase(heap.find(h.second));
}
cur = *heap.rbegin();
if (cur != pre) {
res.push_back({h.first, cur});
pre = cur;
}
}
return res;
}
};
LintCode上也有一道跟这道一样,不过只是输出的结果不同。
http://www.lintcode.com/en/problem/building-outline/
[LeetCode] The Skyline Problem的更多相关文章
- [LeetCode] The Skyline Problem 天际线问题
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
- [LeetCode] 281. The Skyline Problem 天际线问题
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
- [LeetCode] 218. The Skyline Problem 天际线问题
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
- [LeetCode#218] The Skyline Problem
Problem: A city's skyline is the outer contour of the silhouette formed by all the buildings in that ...
- Java for LeetCode 218 The Skyline Problem【HARD】
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
- LeetCode 218. The Skyline Problem 天际线问题(C++/Java)
题目: A city's skyline is the outer contour of the silhouette formed by all the buildings in that city ...
- The Skyline Problem leetcode 详解
class Solution { public: vector<pair<int, int>> getSkyline(vector<vector<int>&g ...
- 218. The Skyline Problem (LeetCode)
天际线问题,参考自: 百草园 天际线为当前线段的最高高度,所以用最大堆处理,当遍历到线段右端点时需要删除该线段的高度,priority_queue不提供删除的操作,要用unordered_map来标记 ...
- The Skyline Problem
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
随机推荐
- jQuery实现页面内锚点平滑跳转
平时我们做导航滚动到内容都是通过锚点来做,刷的一下就直接跳到内容了,没有一丝的滚动效果,而且 url 链接最后会有“小尾巴”,就像#keleyi,今天我就介绍一款 jquery 做的滚动的特效,既可以 ...
- JS高程3.基本概念(3)
1.ECMAScript数值的范围 由于内存的限制,在大多数浏览器中,ECMAScript能够拿保存的数据的范围是 5e-324 ~ 1.7976931348623157e+308,其中最小的数值保存 ...
- python操作SQL
pymysql pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同 一.下载安装 pip3 install pymysql 二.操作使用 1.执行SQL #!/usr ...
- javascript 实现一个回文数字
写一个方法,让"1234"变成回文数字“1234321”,就是顺着读和倒着读都是一样的:注:不让用reverse()方法: function palindrome(str){ va ...
- ASP.NET Mvc实用框架(一)Ioc、仓储模式和单元工作模式
Framework.EF 首先看一下这个类库: Extended文件夹存放的是EntityFramework.Extensions这个插件的源代码,没有别的原因,就是本人觉得这个插件挺好的,每次省的下 ...
- gcc boost版本冲突解决日记
问题背景 项目在Ubuntu10 64位 boost 1.55,boost采用的是项目内包含相对目录的形式部署 项目采用了 -Wall -Wextra -Werror -Wconversion 最高的 ...
- iOS开发之功能模块--Apns推送中的的json格式介绍
在开发向苹果Apns推送消息服务功能,我们需要根据Apns接受的数据格式进行推送.下面接受我在进行apns推送时候总结的一点apns服务接受的Json数据格式 示例 1: 以下负载包含哦一个简单的 a ...
- JavaWeb结合七牛云存储搭建个人相册服务
JavaWeb结合七牛云存储搭建个人相册服务 一.引言1. 课程概述 相信很多人都知道网站一般会有很多图片,对于小型网站来说,图片放在网站服务器上不算什么,但当图片数量很大时,会造成服务器很臃肿,相应 ...
- ORACLE查看补丁出现“OPatch failed with error code 1”
案例场景: 在Oracle Linux Server release 5.7上安装完ORACLE 10g后,顺便将PSR(Patch Set Release)p681018 ...
- ORA-01950: no privileges on tablespace xxxx
案例场景: 新建了一个表空间后TBS_MARKET_DAT,希望将归档的数据放置在这个表空间. SQL> CREATE TABLESPACE TBS_MARKET_DAT 2 DATAFI ...