218. 天际线问题
难度困难256
城市的天际线是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。现在,假设您获得了城市风光照片(图A)上显示的所有建筑物的位置和高度,请编写一个程序以输出由这些建筑物形成的天际线(图B)。
每个建筑物的几何信息用三元组 [Li,Ri,Hi]
表示,其中 Li
和 Ri
分别是第 i 座建筑物左右边缘的 x 坐标,Hi
是其高度。可以保证 0 ≤ Li, Ri ≤ INT_MAX
, 0 < Hi ≤ INT_MAX
和 Ri - Li > 0
。您可以假设所有建筑物都是在绝对平坦且高度为 0 的表面上的完美矩形。
例如,图A中所有建筑物的尺寸记录为:[ [2 9 10], [3 7 15], [5 12 12], [15 20 10], [19 24 8] ]
。
输出是以 [ [x1,y1], [x2, y2], [x3, y3], ... ]
格式的“关键点”(图B中的红点)的列表,它们唯一地定义了天际线。关键点是水平线段的左端点。请注意,最右侧建筑物的最后一个关键点仅用于标记天际线的终点,并始终为零高度。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
例如,图B中的天际线应该表示为:[ [2 10], [3 15], [7 12], [12 0], [15 10], [20 8], [24, 0] ]
。
说明:
- 任何输入列表中的建筑物数量保证在
[0, 10000]
范围内。 - 输入列表已经按左
x
坐标Li
进行升序排列。 - 输出列表必须按 x 位排序。
- 输出天际线中不得有连续的相同高度的水平线。例如
[...[2 3], [4 5], [7 5], [11 5], [12 7]...]
是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]
思路分析?
自己也没有想出来解法,主要参考了下边的几个链接。
https://www.youtube.com/watch?v=GSBLe8cKu0s
https://leetcode.com/problems/the-skyline-problem/discuss/61281/Java-divide-and-conquer-solution-beats-96
虽然明白了上边作者的解法,但并没有像以往一样理出作者是怎么想出解法的,或者说推导有点儿太马后炮了,并不能说服自己,所以下边介绍的解法只讲方法,没有一步一步的递进的过程了。
首先讲一下为什么题目要求我们输出那些关键点,换句话说,知道那些关键点我们怎么画出轮廓。
我们只需要从原点向右出发,沿着水平方向一直画线。
如果在正上方或者正下方遇到关键点,就拐向关键点。
到达关键点后继续向右水平画线,重复上边的过程即可。
可以结合下边的图看一下。
解法一
有些类似归并排序的思想,divide and conquer 。
首先考虑,如果只给一个建筑 [x, y, h]
,那么答案是多少?
很明显输出的解将会是 [[x, h], [y, 0]]
,也就是左上角和右下角坐标。
接下来考虑,如果有建筑 A B C D E,我们知道了建筑 A B C 输出的解和 D E 输出的解,那么怎么把这两组解合并,得到 A B C D E 输出的解。
合并方法采用归并排序中双指针的方法,将两个指针分别指向两组解的开头,然后进行比对。具体的,看下边的例子。
每次选取 x
坐标较小的点,然后再根据一定规则算出高度,具体的看下边的过程。
Skyline1 = {
(1, 11), (3, 13), (9, 0), (12, 7), (16, 0)}
Skyline2 = {
(14, 3), (19, 18), (22, 3), (23, 13), (29, 0)}
Skyline1 存储第一组的解。
Skyline2 存储第二组的解。
Result 存储合并后的解, Result = {
}
h1 表示将 Skyline1 中的某个关键点加入 Result 中时, 当前关键点的高度
h2 表示将 Skyline2 中的某个关键点加入 Result 中时, 当前关键点的高度
h1 = 0, h2 = 0
i = 0, j = 0
(1, 11), (3, 13), (9, 0), (12, 7), (16, 0)
^
i
(14, 3), (19, 18), (22, 3), (23, 13), (29, 0)
^
j
比较 (1, 11) 和 (14, 3)
比较 x 坐标, 1 < 14, 所以考虑 (1, 11)
x 取 1, 接下来更新 height
h1 = 11, height = max(h1, h2) = max(11, 0) = 11
将 (1, 11) 加入到 Result 中
Result = {
(1, 11)}
i 后移, i = i + 1 = 2
(1, 11), (3, 13), (9, 0), (12, 7), (16, 0)
^
i
(14, 3), (19, 18), (22, 3), (23, 13), (29, 0)
^
j
比较 (3, 13) 和 (14, 3)
比较 x 坐标, 3 < 14, 所以考虑 (3, 13)
x 取 3, 接下来更新 height
h1 = 13, height = max(h1, h2) = max(13, 0) = 13
将 (3, 13) 加入到 Result 中
Result = {
(1, 11), (3, 13)}
i 后移, i = i + 1 = 3
(9, 0) 和 (12, 7) 同理
此时 h1 = 7
Result 为 {
(1, 11), (3, 13), (9, 0), (12, 7)}
i = 4
(1, 11), (3, 13), (9, 0), (12, 7), (16, 0)
^
i
(14, 3), (19, 18), (22, 3), (23, 13), (29, 0)
^
j
比较 (16, 0) 和 (14, 3)
比较 x 坐标, 14 < 16, 所以考虑 (14, 3)
x 取 14, 接下来更新 height