forked from yihaoye/data-structure-and-algorithm-study-notes
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path218 The Skyline Problem.java
More file actions
112 lines (93 loc) · 5.05 KB
/
218 The Skyline Problem.java
File metadata and controls
112 lines (93 loc) · 5.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
A city's skyline is the outer contour of the silhouette formed by all the buildings in that city when viewed from a distance. Given the locations and heights of all the buildings, return the skyline formed by these buildings collectively.
The geometric information of each building is given in the array buildings where buildings[i] = [lefti, righti, heighti]:
lefti is the x coordinate of the left edge of the ith building.
righti is the x coordinate of the right edge of the ith building.
heighti is the height of the ith building.
You may assume all buildings are perfect rectangles grounded on an absolutely flat surface at height 0.
The skyline should be represented as a list of "key points" sorted by their x-coordinate in the form [[x1,y1],[x2,y2],...]. Each key point is the left endpoint of some horizontal segment in the skyline except the last point in the list, which always has a y-coordinate 0 and is used to mark the skyline's termination where the rightmost building ends. Any ground between the leftmost and rightmost buildings should be part of the skyline's contour.
Note: 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],...]
Example 1:
https://assets.leetcode.com/uploads/2020/12/01/merged.jpg
Input: buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]]
Output: [[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]]
Explanation:
Figure A shows the buildings of the input.
Figure B shows the skyline formed by those buildings. The red points in figure B represent the key points in the output list.
Example 2:
Input: buildings = [[0,2,3],[2,5,3]]
Output: [[0,3],[5,0]]
Constraints:
1 <= buildings.length <= 104
0 <= lefti < righti <= 231 - 1
1 <= heighti <= 231 - 1
buildings is sorted by lefti in non-decreasing order.
*/
// Other's Solution:
class Solution {
public List<List<Integer>> getSkyline(int[][] bs) {
/*
扫描线
- https://leetcode-cn.com/problems/the-skyline-problem/solution/gong-shui-san-xie-sao-miao-xian-suan-fa-0z6xc/
- http://zxi.mytechroad.com/blog/tree/leetcode-218-the-skyline-problem/
Time O(N*logN),Space O(N)
*/
List<List<Integer>> res = new ArrayList<>();
List<int[]> ps = new ArrayList<>();
for (int[] b : bs) {
int l = b[0], r = b[1], h = b[2];
ps.add(new int[]{l, h, -1});
ps.add(new int[]{r, h, 1});
}
/**
* 先严格按照横坐标进行「从小到大」排序
* 对于某个横坐标而言,可能会同时出现多个点,应当按照如下规则进行处理:
* 1. 优先处理左端点,再处理右端点
* 2. 如果同样都是左端点,则按照高度「从大到小」进行处理(将高度增加到优先队列中)
* 3. 如果同样都是右端点,则按照高度「从小到大」进行处理(将高度从优先队列中删掉)
*/
Collections.sort(ps, (a, b)->{
if (a[0] != b[0]) return a[0] - b[0];
if (a[2] != b[2]) return a[2] - b[2];
if (a[2] == -1) {
return b[1] - a[1];
} else {
return a[1] - b[1];
}
});
// 由于优先队列的 remove 操作需要先经过 O(N) 的复杂度进行查找,再通过 O(logN) 的复杂度进行删除。因此整个 remove 操作的复杂度是 O(N) 的,这导致了算法整体复杂度为 O(n^2)。
// 优化方式包括:使用基于红黑树的 TreeMap 代替优先队列;或是使用哈希表记录"执行了删除操作的高度"及"删除次数",在每次使用前先检查堆顶高度是否已经被标记删除,如果是则进行 poll 操作,并更新删除次数,直到遇到一个没被删除的堆顶高度。
// 记录进行了删除操作的高度,以及删除次数
Map<Integer, Integer> map = new HashMap<>();
PriorityQueue<Integer> q = new PriorityQueue<>((a,b)->b-a);
int prev = 0;
q.add(prev);
for (int[] p : ps) {
int point = p[0], height = p[1], flag = p[2];
if (flag == -1) {
q.add(height);
} else {
map.put(height, map.getOrDefault(height, 0) + 1);
}
while (!q.isEmpty()) {
int peek = q.peek();
if (map.containsKey(peek)) {
if (map.get(peek) == 1) map.remove(peek);
else map.put(peek, map.get(peek) - 1);
q.poll();
} else {
break;
}
}
int cur = q.peek();
if (cur != prev) {
List<Integer> list = new ArrayList<>();
list.add(point);
list.add(cur);
res.add(list);
prev = cur;
}
}
return res;
}
}