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_MAX0 < 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的更多相关文章

  1. [LeetCode] The Skyline Problem 天际线问题

    A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...

  2. [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 ...

  3. [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 ...

  4. [LeetCode#218] The Skyline Problem

    Problem: A city's skyline is the outer contour of the silhouette formed by all the buildings in that ...

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

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

  7. The Skyline Problem leetcode 详解

    class Solution { public: vector<pair<int, int>> getSkyline(vector<vector<int>&g ...

  8. 218. The Skyline Problem (LeetCode)

    天际线问题,参考自: 百草园 天际线为当前线段的最高高度,所以用最大堆处理,当遍历到线段右端点时需要删除该线段的高度,priority_queue不提供删除的操作,要用unordered_map来标记 ...

  9. The Skyline Problem

    A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...

随机推荐

  1. 标准BST二叉搜索树写法

    本人最近被各种数据结构的实验折磨的不要不要的,特别是代码部分,对数据结构有严格的要求,比如写个BST要分成两个类,一个节点类,要给树类,关键是所以操作都要用函数完成,也就是在树类中不能直接操作节点,需 ...

  2. VS2015搭建GoogleTest框架--配置第一个项目

    最近公司要我学习Google的测试框架google test:https://github.com/google/googletest. GoogleTest是C++的测试框架,我一个学习Java的, ...

  3. Android中Listview展示及其优化好处

    展示效果: 中间的item条目是可以上下滑动的. 代码实现: @Override public View getView(int position, View convertView, ViewGro ...

  4. JDBC快速入门

    /** * JDBC快速入门: * 1.导入jar包 数据库驱动 * 2.注册驱动 * 3.获取数据库连接对象 Connection * 4.定义sql语句 * 5.获取发送执行sql语句的对象 St ...

  5. 初学RunLoop

    RunLoop 运行循环,跑圈 可以看出每条线程都有一个与之对应的RunLoop对象 主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建. 基本作用:保持程序的持续运行 处理A ...

  6. Android中Listview点击item不变颜色以及设置listselector 无效

    Android中Listview点击item不变颜色以及设置listselector 无效 这是同一个问题,Listview中点击item是会变颜色的,因为listview设置了默认的listsele ...

  7. Appfuse:起步

    在众多开源的Java开源CMS中探索了很久,终于选定了appfuse,理由如下: 1. 简洁:只搭建了框架,没有做多余的事 2. 完成了基本的用户管理:用户.角色.权限的定义很清晰 3. 符合预期的架 ...

  8. JavaScript语言精粹(读书笔记)

    第一章 精华 1,JavaScript的函数(主要)基于词法作用域(lexical scoping)的顶级对象.强类型语言允许编译器在编译时检测错误,但弱类型很自由,无需建立复杂的类层次,不用做强制造 ...

  9. Git 技能总结

    创建和使用git ssh key 首先设置git的user name和email: git config --global user.name "xxx" git config - ...

  10. [Erlang 0103] Erlang Resources 资讯小站

       好久没有写博客,是懒了吗?不是;前面两个月在紧张地推进一个项目,中间积累了一些RabbitMQ和Erlang的东西;本打算在项目结束之后赶紧总结一下,结果老婆怀孕之后生活节奏大乱:早起做饭,晚上 ...