218. 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 aregiven 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], ...]
链接: http://leetcode.com/problems/the-skyline-problem/
题解:
很经典的题目。一开始的想法是遍历一遍数组,然后把所有关键点及其长度计算出来,再遍历一遍数组,找到所有结果。没有尝试。
后来研究了Discuss,发现有两种做法:
- 一种是用Mergesort的原理。
- 首先base case是当我们递归函数的lo == hi时,这时只有一个building,由一个building形成一个skyline。这里我们的两个关键点是(left, height)以及(right,0)。
- 有了skyline之后我们就可以进行推广。每个skyline都已经是一个left sorted的doubly linkedlist。 每次由两个skyline merge成一个更大的skyline,最后一步步得出结果。 这里merge函数跟"Merge Two Sorted List" 很象。要注意merge时的各种判断,我们需要current height1和current height2来cache skyline1和skyline2的当前高度。而最后加入结果的height为Math.max(skyline1 current height,skyline2 current height),加入结果的index为两个skyline元素中最左边的那一个,之后还要把处理过的元素从skyline1或者2,或者1和2里去除掉。所以这里用doubly-linked list很方便,其实用queue或者deque也能有一样的效果。
- merge是一个O(n)的操作,而总算法的时间复杂度是O(nlogn),空间复杂度是O(n)。
- 另外一种是维护一个heap,用Sweepling Algorithm在heap里面增删改,最后输出结果。
Divide and Conquer:
Time Complexity - O(nlogn), Space Complexity - O(n)
public class Solution {
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);
skyline1.removeFirst();
} else if (skyline1.getFirst()[0] > skyline2.getFirst()[0]) {
index = skyline2.getFirst()[0];
height2 = skyline2.getFirst()[1];
height = Math.max(height1, height2);
skyline2.removeFirst();
} else {
index = skyline1.getFirst()[0];
height1 = skyline1.getFirst()[1];
height2 = skyline2.getFirst()[1];
height = Math.max(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;
} }
Sweeping line + Heap: (二刷再解决)
二刷:
二刷依然是使用了Divide and Conquer。使用了ArrayList来保存结果,虽然代码长一点,但速度更快,并且更容易理解一点点。
要注意的还是在merge的时候:
- 我们仍然要保存之前的height1和height2两个变量。
- 对skyline1和skyline2中的第一个点p1和p2,我们分三种情况
- p1[0] < p2[0],这时候p1在p2之前出现,我们更新height1 = p1[1],先处理p1
- p1[0] > p2[0],这时候p1在p2之后出现,我们更新height2 = p2[1],先处理p2
- 否则两点同时出现,我们更新height1和height2,同时处理两个点
- 在height = max(height1, height2),并且height != res.get(res.size() - 1)时,也就是当前这个点的高度不等于之前点的高度,我们把这个点加入到结果集res中。这里的一个小边界条件是当res.size() == 0时,我们也加入这个点[index, height]。
- 在merge的最后我们要判断一下是否skyline1或者skyline2中所有的点都计算过了。 假如还有剩余点,我们对其进行处理。
也可以用一些特殊的数据结构来做,比如PQ + Sweeping line, Treap, Fenwick Tree等等。 下次再研究。
Java:
Time Complexity - O(nlogn), Space Complexity - O(n)
public class Solution {
public List<int[]> getSkyline(int[][] buildings) {
if (buildings == null || buildings.length == 0) return new ArrayList<int[]>();
return getSkyline(buildings, 0, buildings.length - 1);
} private List<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 {
List<int[]> res = new ArrayList<>();
res.add(new int[] {buildings[lo][0], buildings[lo][2]});
res.add(new int[] {buildings[lo][1], 0});
return res;
}
} private List<int[]> mergeSkylines(List<int[]> skyline1, List<int[]> skyline2) {
List<int[]> res = new ArrayList<>();
int i = 0, j = 0;
int index = 0, height = 0, height1 = 0, height2 = 0; while (i < skyline1.size() && j < skyline2.size()) {
int[] p1 = skyline1.get(i);
int[] p2 = skyline2.get(j);
if (p1[0] < p2[0]) {
index = p1[0];
height1 = p1[1];
i++;
} else if (p1[0] > p2[0]) {
index = p2[0];
height2 = p2[1];
j++;
} else {
index = p1[0];
height1 = p1[1];
height2 = p2[1];
i++;
j++;
}
height = Math.max(height1, height2);
if (res.size() == 0 || height != res.get(res.size() - 1)[1]) res.add(new int[] {index, height});
} if (i < skyline1.size()) {
for (int k = i; k < skyline1.size(); k++) {
int[] p1 = skyline1.get(k);
if (p1[1] != res.get(res.size() - 1)[1]) res.add(p1);
}
} else if (j < skyline2.size()){
for (int k = j; k < skyline2.size(); k++) {
int[] p2 = skyline2.get(k);
if (p2[1] != res.get(res.size() - 1)[1]) res.add(p2);
}
}
return res;
}
}
Reference:
https://en.wikipedia.org/wiki/Sweep_line_algorithm#Applications
http://www.algorithmist.com/index.php/UVa_105
http://www.cnblogs.com/easonliu/p/4531020.html
https://cseweb.ucsd.edu/classes/sp04/cse101/skyline.pdf
http://sandrasi-sw.blogspot.com/2012/12/the-skyline-problem.html
http://www.geeksforgeeks.org/divide-and-conquer-set-7-the-skyline-problem/
https://briangordon.github.io/2014/08/the-skyline-problem.html
https://leetcode.com/discuss/61274/17-line-log-time-space-accepted-easy-solution-explanations
https://leetcode.com/discuss/37630/my-c-code-using-one-priority-queue-812-ms
https://leetcode.com/discuss/37736/108-ms-17-lines-body-explained
https://leetcode.com/discuss/40963/share-my-divide-and-conquer-java-solution-464-ms
https://leetcode.com/discuss/54201/short-java-solution
https://leetcode.com/discuss/88149/java-solution-using-priority-queue-and-sweepline
218. The Skyline Problem的更多相关文章
- [LeetCode#218] The Skyline Problem
Problem: A city's skyline is the outer contour of the silhouette formed by all the buildings in that ...
- [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 ...
- 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 ...
- 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 ...
- 218. The Skyline Problem (LeetCode)
天际线问题,参考自: 百草园 天际线为当前线段的最高高度,所以用最大堆处理,当遍历到线段右端点时需要删除该线段的高度,priority_queue不提供删除的操作,要用unordered_map来标记 ...
- [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] The Skyline Problem
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
- The Skyline Problem
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city whe ...
随机推荐
- Codevs 2296 仪仗队 2008年省队选拔赛山东
2296 仪仗队 2008年省队选拔赛山东 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 大师 Master 题解 题目描述 Description 作为体育委员,C君负责这次运动 ...
- myeclipse 的 working set
想必大家的myeclipse会有很多工程看的和不方便,那么怎么让它看的简洁一点呢,使用working set 会让你的目录看起来没有那么的多. 首先是怎么创建 working set ,在新建时选择 ...
- JS焦点图,JS 多个页面放多个焦点图
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- ListView练习
1. 在 .xml中创建一个ListView是不会显示出来的. 2. ListView的Item: 列表项, 3. 显示ListView的4个要素: 3.1 ListView控件:在layout布局中 ...
- eclipse 安装egit 成功后Team中没有显示
主要是版本不太对. 在http://wiki.eclipse.org/EGit/FAQ#Where_can_I_find_older_releases_of_EGit.3F 中找到对应的版本,设置就O ...
- C# window service的创建
其实我也是第一次在博客园写博客,看到那些高手说自己要多动手写博客,于是乎自己也尝试尝试. 废话不多说.这几天在研究window service,通过查找各种大神写的博客,我终于成功的自己写出来了. 下 ...
- ffmpeg yuv转h264
ffmpeg -s 176x144 -i container_qcif_176_144.yuv -b:v 7776k -r 25 -vcodec libx264 ds.h264
- WinForm调试输出数据
在调试Winfrom时想知道其中的数据输出 1.单击运行按钮 2.选择调试->窗口->输出 3.单击Winform中要执行的按钮 在输出栏中显示输出数据 4.Ctrl K S 能够 ...
- sysfs接口整理
SYS节点 目录结构: 1:sysfs相关知识点介绍(介绍sysfs的体系结构) 2:sys节点核心知识(使用sys节点核心的知识) 3:代码实例(创建sys节点的代码实例) 1:sysfs相关知识点 ...
- 【socket】Socket的三个功能类TCPClient、TCPListener 和 UDPClient
Socket的三个功能类TCPClient.TCPListener 和 UDPClient (转) 应用程序可以通过 TCPClient.TCPListener 和 UDPClient 类使用传输控制 ...