LeetCode_The Skyline Problem
Posted rotk2015
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode_The Skyline Problem相关的知识,希望对你有一定的参考价值。
-
自己的一开始的想法将 x 轴抽象成一个数组,然后遍历一次建筑群,每遇到新一个建筑,就更新对应的子数组高度。最后将整个数组再遍历一次即可。这个思路很简单,但是存在一个问题,就是维护的数组长度,与建筑群的总占地宽度与要求的输出精度相关,这样在极端条件下,可能会造成很大的空间浪费。同时,这种做法在最后遍历数组时,我们可以发现,有大量的重复数组值是无用的。
-
后来看了下评论区和网上的资料,得到一个比较好的方案。
-
仔细观察可以发现:天际线的 key point 由建筑的边界构成。而建筑之间经常会有覆盖现象,如 [[2,9,10],[3,7,15]],这意味着在以建筑为单位处理时,我们要时不时的走回头路,更新之前已经赋值的高度。那么我们能否在扫描赋值时就盖棺定论,一次遍历即得到正确答案呢?
-
我们可将表示一个建筑的三元数组拆分成两个 <端点,高度> 的二元组,表示一个建筑的起点、终点。将所有建筑的二元组排序,然后遍历处理这些二元组即可。
-
代码如下:
public List<List<Integer>> getSkyline(int[][] buildings) List<List<Integer>> res = new ArrayList<>(); List<int[]> points = new ArrayList<>(); for(int[] b : buildings) points.add(new int[]b[0], -b[2]); // for the start node we use negative value. // 1. to distinguish between end and start node. 2. if there are two adjacent rectangles, the right start // node will be added to heap BEFORE we delete the left end node (because points is ASCENDING order // according to point[0] and point[1]). THEN, when we delete the end node, we can IMMEDIATELY UPDATE the // curMax to start node (if it's right), since we added start node IN ADVANCE. points.add(new int[]b[1], b[2]); Collections.sort(points, (a, b) -> if(a[0]==b[0]) return a[1]-b[1]; else return a[0]-b[0]; ); TreeMap<Integer, Integer> map = new TreeMap<>(); // k is height and v is total numbers. // TreeMap is ascending order according to the key value by default. int prevMax = 0; map.put(0,1); for(int[] p : points) //p[0] is x position and p[1] is height. if(p[1] < 0) map.put(-p[1], map.getOrDefault(-p[1], 0)+1); // put the start point and increase corresponding v. else if(map.get(p[1])>1) map.put(p[1], map.get(p[1])-1); else map.remove(p[1]); int curMax = map.lastKey(); // get highest node of cur heap. if(curMax != prevMax) res.add(Arrays.asList(p[0], curMax)); // x position is p[0] since curMax changed in this step. prevMax = curMax; return res;
参考资料:
以上是关于LeetCode_The Skyline Problem的主要内容,如果未能解决你的问题,请参考以下文章