Leetcode 218. The Skyline Problem 2016/10/5 UPDATE

原创 2016年05月31日 06:40:33

218. The Skyline Problem

Total Accepted: 25930 Total Submissions: 105884 Difficulty: Hard

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.

Hide Company Tags
 Microsoft Google Facebook Twitter Yelp




思路:

参考这里


首先这个矩形已经排序。那么每当高度大于当前最大高度的时候,就会出现一个key point。那么重点就是要知道什么时候当前矩阵应该被remove了。

参考的做法非常巧妙,先是预处理了一下数据,把每个矩形拆成[left, height]和[right, height]。并且把其中之一的高度标为负值,这样就知道这时候该remove这个高度的矩形了。

维护一个最大堆,保存各种height值。这样每当碰到right就出一个对应的height值。


注意以下这些点:

1.可以新建一个数据结构或者直接使用int[]来保存

2.处理过后的数据的compare函数应该是如果坐标相同,那么后来的int[]应该排前面,也就是b[1]-a[1]。否则会出现多余的key point。

3.java默认是最小堆,所以需要自建最大堆并重写compare函数。

4.堆里面要先放入一个0。并且还要维护一个prev来代表之前的高度,这样在当前元素操作之后,可以对比peek(),如果不相等说明有新的key point产生。


感觉自己写compare函数的时候各种)}错位,还需要多练习,要不然面试官站一边就出事了,发挥肯定会更差。


网上还有其他解法,不过就这个解最straightforward,也便于边解释边code。

public class Solution { // 250ms
    public List<int[]> getSkyline(int[][] buildings) {
        List<int[]> res = new ArrayList<int[]>();
        List<int[]> data = new ArrayList<int[]>();
        for(int i=0; i<buildings.length; i++){
            data.add(new int[]{buildings[i][0], buildings[i][2]}); // !!! use int[] instead of int[2]
            data.add(new int[]{buildings[i][1], -buildings[i][2]});
        }
        
        Collections.sort(data, new Comparator<int[]>(){
            public int compare(int[] a, int[] b){
                if(a[0]!=b[0]) return a[0]-b[0];
                else return b[1]-a[1]; // so that next block comes before cur block ends
            }    
        }); // !!!!!!
        
        PriorityQueue<Integer> max = new PriorityQueue<Integer>(15, new Comparator<Integer>(){
            public int compare(Integer i1, Integer i2){
                return i2-i1;
            }
        }); // !!!!!!
        
        max.add(0);
        int prevH = 0;
        for(int i=0; i<data.size(); i++){
            int[] cur = data.get(i);
            if(cur[1]<0) {
                max.remove(-cur[1]); 
            }else{
                max.add(cur[1]);
            }
            int curH = max.peek();
            if(curH!=prevH) {
                res.add(new int[]{cur[0], curH});
                prevH = curH;
            }
        }
        return res;
    }
}

10/5 UPDATE:

解法二:

类似mergesort。参考这里。这个blog很犀利,基本都是各种最快解法和最neat的code。

如果size不为1,就继续递归。直到只有一个building,然后代码干的事情是把这个building一分为二,产生了俩区间[left, height] 和 [right, 0],装在一个LinkList<int[]>中。

然后就是merge。就拿最基本的case说,左右俩building都变成了base case,各返回了俩LinkedList l1和l2,分别包含了上面的俩区间。

merge的过程是:判断俩building的起始位置:

1. l1的起始位置靠前,那么有可能加入的点的index被赋值为该位置,有可能加入的点的高度height = 之前height值和目前这个building的最大值。之后从l1中删除这个区间。

2. l2的起始位置靠前,那么有可能加入的点的index被赋值为该位置,有可能加入的点的高度height = 之前height值和目前这个building的最大值。之后从l2中删除这个区间。

3. 俩building的起始位置相同。那么就都取出来,比较高度,height被更新为这两者height1和height2的最大值。l1和l2都删除头元素。

入结果LinkedList的时候:

如果结果的size为0,那么就可以入,之前没有building;否则如果height和之前的元素不一致则入队。


下面举例:

Input:
[[0,2,3],[2,5,3]]
Expected:
[[0,3],[5,0]]


左边的建筑base case之后返回一个 {[0,3], [2, 0]}

右边的建筑base case之后返回 {[2, 3], [5, 0]}

新建一个list res作为结果,height1 = 0,heitight2 = 0。进入merge while循环:

1. index = 0, height = 0。然后因为0 < 2,进入第一个if,height被更新为3,index为0,height1=3,然后l1 List中删除[0, 3]

这时: {[2, 0]}  {[2, 3], [5, 0]}。结果List res中没有任何元素,加入[0, 3]。

2. index = 0, height = 0,头元素2=2,这样进入第三个block。index = 2, 然后俩List都删除头元素,height1 = 0, height2 = 3,height = max值3。也就是本次的待加入为[2, 3]。然后判断结果List不为空,并且结尾最后一个元素的height=3和当前待加入的元素相等,于是舍弃。

3. 这时一个LIST为空,跳出while循环,加入剩下的元素[5, 0]。

输出:[0, 3] [5, 0]。


public class Solution { // 11ms
    public List<int[]> getSkyline(int[][] buildings) {
        if(buildings == null || buildings.length == 0)
            return new LinkedList<int[]>();
        return getSkyline(buildings, 0, buildings.length - 1);
    }
    
    private LinkedList<int[]> getSkyline(int[][] buildings, int lo, int hi) {
        if(lo < hi) {
            int mid = lo + (hi - lo) / 2;
            return mergeSkylines(getSkyline(buildings, lo, mid), getSkyline(buildings, mid + 1, hi));
        } else {                //  lo == hi, base case, add one building to skyline
            LinkedList<int[]> skyline = new LinkedList<int[]>();
            skyline.add(new int[]{buildings[lo][0], buildings[lo][2]});
            skyline.add(new int[]{buildings[lo][1], 0});
            return skyline;
        } 
    }
    
    private LinkedList<int[]> mergeSkylines(LinkedList<int[]> skyline1, LinkedList<int[]> skyline2) {  // merge two Skylines
        LinkedList<int[]> skyline = new LinkedList<int[]>();
        int height1 = 0, height2 = 0;
        
        while(skyline1.size() > 0 && skyline2.size() > 0) {
            int index = 0, height = 0;
            if(skyline1.getFirst()[0] < skyline2.getFirst()[0]) {
                index = skyline1.getFirst()[0];
                height1 = skyline1.getFirst()[1];
                height = Math.max(height1, height2); // 左边的index小,说明height2仍然有效
                skyline1.removeFirst();
            } else if (skyline1.getFirst()[0] > skyline2.getFirst()[0]) {
                index = skyline2.getFirst()[0];
                height2 = skyline2.getFirst()[1];
                height = Math.max(height1, height2); <span style="font-family: Arial, Helvetica, sans-serif;">//右边的index小,说明height1仍然有效</span>
                skyline2.removeFirst();
            } else {
                index = skyline1.getFirst()[0];
                height1 = skyline1.getFirst()[1];
                height2 = skyline2.getFirst()[1];
                height = Math.max(height1, height2); // 之前的height1 和 height2 都失效
                skyline1.removeFirst();
                skyline2.removeFirst();
            }
            if(skyline.size() == 0 || height != skyline.getLast()[1])
                skyline.add(new int[]{index, height});
        }
        skyline.addAll(skyline1);
        skyline.addAll(skyline2);
      
        return skyline;
    }
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

[leetcode] 218.The Skyline Problem

题目: A city’s skyline is the outer contour of the silhouette formed by all the buildings in that cit...

leetcode 218. The Skyline Problem java代码

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[hard]

题目: A city’s skyline is the outer contour of the silhouette formed by all the buildings in that cit...

LeetCode218. The Skyline Problem分治法

题意:轮廓问题,不好描述。首先怎么分: 不停对半分 停止条件1:为空时,直接返回空 停止条件2:大小为1时,直接返回左上角点和右下角点。 那么怎么合并? 维护两个变量:l,r l为左半部分当前位置,r...

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

A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe...
  • sbitswc
  • sbitswc
  • 2015年10月08日 14:51
  • 1268

[leetcode] 218. The Skyline Problem 解题报告

题目链接: https://leetcode.com/problems/the-skyline-problem/ A city's skyline is the outer contour of ...

LeetCode 218. The Skyline Problem(天际线)

原题网址:https://leetcode.com/problems/the-skyline-problem/ A city's skyline is the outer contour of t...
  • jmspan
  • jmspan
  • 2016年05月06日 07:03
  • 647

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

218. The Skyline Problem

A city’s skyline is the outer contour of the silhouette formed by all the buildings in that city whe...
  • zsjmfy
  • zsjmfy
  • 2017年03月26日 15:51
  • 165
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Leetcode 218. The Skyline Problem 2016/10/5 UPDATE
举报原因:
原因补充:

(最多只允许输入30个字)