zoukankan      html  css  js  c++  java
  • [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).

    Buildings Skyline Contour

    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的代码。

     1 class Solution {
     2 private:
     3     enum NODE_TYPE {LEFT, RIGHT};
     4     struct node {
     5         int x, y;
     6         NODE_TYPE type;
     7         node(int _x, int _y, NODE_TYPE _type) : x(_x), y(_y), type(_type) {}
     8     };
     9     
    10 public:
    11     vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
    12         vector<node> height;
    13         for (auto &b : buildings) {
    14             height.push_back(node(b[0], b[2], LEFT));
    15             height.push_back(node(b[1], b[2], RIGHT));
    16         }
    17         sort(height.begin(), height.end(), [](const node &a, const node &b) {
    18             if (a.x != b.x) return a.x < b.x;
    19             else if (a.type == LEFT && b.type == LEFT) return a.y > b.y;
    20             else if (a.type == RIGHT && b.type == RIGHT) return a.y < b.y;
    21             else return a.type == LEFT;
    22         });
    23         
    24         priority_queue<int> heap;
    25         unordered_map<int, int> mp;
    26         heap.push(0);
    27         vector<pair<int, int>> res;
    28         int pre = 0, cur = 0;
    29         for (auto &h : height) {
    30             if (h.type == LEFT) {
    31                 heap.push(h.y);
    32             } else {
    33                 ++mp[h.y];
    34                 while (!heap.empty() && mp[heap.top()] > 0) {
    35                     --mp[heap.top()];
    36                     heap.pop();
    37                 }
    38             }   
    39             cur = heap.top();
    40             if (cur != pre) {
    41                 res.push_back({h.x, cur});
    42                 pre = cur;
    43             }
    44         }
    45         return res;
    46     }
    47 };

    使用一些技巧可以大大减少编码的复杂度,priority_queue并没有提供erase操作,但是multiset提供了,而且multiset内的数据是按BST排好序的。在区分左右节点时,我之前自己建了一个结构体,用一个属性type来标记。这里可以用一个小技巧,那就是把左边节点的高度值设成负数,右边节点的高度值是正数,这样我们就不用额外的属性,直接用pair<int, int>就可以保存了。而且对其排序,发现pair默认的排序规则就已经满足要求了。

     1 class Solution {
     2 public:
     3     vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) {
     4         vector<pair<int, int>> height;
     5         for (auto &b : buildings) {
     6             height.push_back({b[0], -b[2]});
     7             height.push_back({b[1], b[2]});
     8         }
     9         sort(height.begin(), height.end());
    10         multiset<int> heap;
    11         heap.insert(0);
    12         vector<pair<int, int>> res;
    13         int pre = 0, cur = 0;
    14         for (auto &h : height) {
    15             if (h.second < 0) {
    16                 heap.insert(-h.second);
    17             } else {
    18                 heap.erase(heap.find(h.second));
    19             }   
    20             cur = *heap.rbegin();
    21             if (cur != pre) {
    22                 res.push_back({h.first, cur});
    23                 pre = cur;
    24             }
    25         }
    26         return res;
    27     }
    28 };

    LintCode上也有一道跟这道一样,不过只是输出的结果不同。

    http://www.lintcode.com/en/problem/building-outline/

  • 相关阅读:
    es6中promise的实现及原理
    移动端
    javascript知识点复习
    html和css基本常识总结
    kafka,查看指定group下topic的堆积数量
    解决问题:Android设备运行自动化脚本报错 ioerror RPC server not started
    linux下安装python3
    使用vsftpd搭建FTP服务
    前端性能监控平台showslow+Yslow搭建
    学习笔记-- Python网络编程
  • 原文地址:https://www.cnblogs.com/easonliu/p/4531020.html
Copyright © 2011-2022 走看看