[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 ...
随机推荐
- 缓存、队列(Memcached,Redis,rabbitMQ)
一.Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的 ...
- iOS 怎么设置 UITabBarController 的第n个item为第一响应者?
iOS 怎么设置 UITabBarController 的第n个item为第一响应者? UITabBarController 里面有个属性:selectedIndex @property(nonato ...
- AFNetworking的理解
AFNetworking的理解 使用方法 1. 新建的工程中导入AFNetworking3.0中的(AFNetworking 和UIKit+AFNetworking两个文件夹) 2. 在用到AFNet ...
- UIView
//command+R 运行 //command+. 停止 //command+B 预编译 //command+1.2.3 模拟器大小 //command+shift+h home键 ...
- Tableview中Dynamic Prototypes动态表的使用
Tableview时IOS中应用非常广泛的控件,当需要动态的添加多条不同的数据时,需要用动态表来实现,下面给出一个小例子,适用于不确定Section的数目,并且每个Section中的行数也不同的情况, ...
- fillStyle径向渐变
<!DOCTYPE HTML> <head> <meta charset = "utf-8"> <title>canvas</ ...
- #研发中间件介绍#异步消息可靠推送Notify
郑昀 基于朱传志的设计文档 最后更新于2014/11/11 关键词:异步消息.订阅者集群.可伸缩.Push模式.Pull模式 本文档适用人员:研发 电商系统为什么需要 NotifyServer? ...
- Java暗箱操作之自动装箱与拆箱
我以前在写Android项目的时候,估计写得最多最熟练的几句话就是: List<Integer> list = new ArrayList<Integer>(); list.a ...
- SQL SERVER 2000通过链接服务器发送邮件出现错误
案例环境: 服务器A系统: Windows Server 2000 数据库版本 : Microsoft SQL Server 2000 - 8.00.2282 (Intel X86) 服务器B系统: ...
- DbVisualizer连接hbase
1.添加phoneix驱动 (1).点击Tools--->Driver Manager- (2).新建一个驱动,名称为phoenix(名称随意),选择phoenix的客户端驱动,驱动类如图所示 ...