218. 天际线问题
城市的 天际线 是从远处观看该城市中所有建筑物形成的轮廓的外部轮廓。给你所有建筑物的位置和高度,请返回 由这些建筑物形成的 天际线 。
每个建筑物的几何信息由数组 buildings
表示,其中三元组 buildings[i] = [lefti, righti, heighti]
表示:
lefti
是第 i
座建筑物左边缘的 x
坐标。righti
是第 i
座建筑物右边缘的 x
坐标。heighti
是第 i
座建筑物的高度。你可以假设所有的建筑都是完美的长方形,在高度为 0
的绝对平坦的表面上。
天际线 应该表示为由 “关键点” 组成的列表,格式 [[x1,y1],[x2,y2],...]
,并按 x 坐标 进行 排序 。关键点是水平线段的左端点。列表中最后一个点是最右侧建筑物的终点,y
坐标始终为 0
,仅用于标记天际线的终点。此外,任何两个相邻建筑物之间的地面都应被视为天际线轮廓的一部分。
注意:输出天际线中不得有连续的相同高度的水平线。例如 [...[2 3], [4 5], [7 5], [11 5], [12 7]...]
是不正确的答案;三条高度为 5 的线应该在最终输出中合并为一个:[...[2 3], [4 5], [12 7], ...]
示例 1:
输入:buildings = [[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]] 输出:[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]] 解释: 图 A 显示输入的所有建筑物的位置和高度, 图 B 显示由这些建筑物形成的天际线。图 B 中的红点表示输出列表中的关键点。
示例 2:
输入:buildings = [[0,2,3],[2,5,3]] 输出:[[0,3],[5,0]]
提示:
1 <= buildings.length <= 104
0 <= lefti < righti <= 231 - 1
1 <= heighti <= 231 - 1
buildings
按 lefti
非递减排序相似题目
原站题解
python3 解法, 执行用时: 104 ms, 内存消耗: 21.7 MB, 提交时间: 2023-09-05 10:28:45
from sortedcontainers import SortedList class Solution: def getSkyline(self, buildings: List[List[int]]) -> List[List[int]]: ans = [] # 预处理所有的点,为了方便排序,对于左端点,令高度为负;对于右端点令高度为正 ps = [] for l, r, h in buildings: ps.append((l, - h)) ps.append((r, h)) # 先按照横坐标进行排序 # 如果横坐标相同,则按照左端点排序 # 如果相同的左/右端点,则按照高度进行排序 ps.sort() prev = 0 # 有序列表充当大根堆 q = SortedList([prev]) for point, height in ps: if height < 0: # 如果是左端点,说明存在一条往右延伸的可记录的边,将高度存入优先队列 q.add(-height) else: # 如果是右端点,说明这条边结束了,将当前高度从队列中移除 q.remove(height) # 取出最高高度,如果当前不与前一矩形“上边”延展而来的那些边重合,则可以被记录 cur = q[-1] if cur != prev: ans.append([point, cur]) prev = cur return ans
cpp 解法, 执行用时: 28 ms, 内存消耗: 13.5 MB, 提交时间: 2023-09-05 10:28:26
class Solution { public: vector<vector<int>> getSkyline(vector<vector<int>>& buildings) { auto cmp = [](const pair<int, int>& a, const pair<int, int>& b) -> bool { return a.second < b.second; }; priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(cmp)> que(cmp); vector<int> boundaries; for (auto& building : buildings) { boundaries.emplace_back(building[0]); boundaries.emplace_back(building[1]); } sort(boundaries.begin(), boundaries.end()); vector<vector<int>> ret; int n = buildings.size(), idx = 0; for (auto& boundary : boundaries) { while (idx < n && buildings[idx][0] <= boundary) { que.emplace(buildings[idx][1], buildings[idx][2]); idx++; } while (!que.empty() && que.top().first <= boundary) { que.pop(); } int maxn = que.empty() ? 0 : que.top().second; if (ret.size() == 0 || maxn != ret.back()[1]) { ret.push_back({boundary, maxn}); } } return ret; } };
java 解法, 执行用时: 16 ms, 内存消耗: 45.1 MB, 提交时间: 2023-09-05 10:27:27
class Solution { public List<List<Integer>> getSkyline(int[][] buildings) { PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> b[1] - a[1]); List<Integer> boundaries = new ArrayList<Integer>(); for (int[] building : buildings) { boundaries.add(building[0]); boundaries.add(building[1]); } Collections.sort(boundaries); List<List<Integer>> ret = new ArrayList<List<Integer>>(); int n = buildings.length, idx = 0; for (int boundary : boundaries) { while (idx < n && buildings[idx][0] <= boundary) { pq.offer(new int[]{buildings[idx][1], buildings[idx][2]}); idx++; } while (!pq.isEmpty() && pq.peek()[0] <= boundary) { pq.poll(); } int maxn = pq.isEmpty() ? 0 : pq.peek()[1]; if (ret.size() == 0 || maxn != ret.get(ret.size() - 1).get(1)) { ret.add(Arrays.asList(boundary, maxn)); } } return ret; } }
golang 解法, 执行用时: 8 ms, 内存消耗: 6.7 MB, 提交时间: 2023-09-05 10:27:15
// 扫描线 + 优先队列 type pair struct{ right, height int } type hp []pair func (h hp) Len() int { return len(h) } func (h hp) Less(i, j int) bool { return h[i].height > h[j].height } func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *hp) Push(v interface{}) { *h = append(*h, v.(pair)) } func (h *hp) Pop() interface{} { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v } func getSkyline(buildings [][]int) (ans [][]int) { n := len(buildings) boundaries := make([]int, 0, n*2) for _, building := range buildings { boundaries = append(boundaries, building[0], building[1]) } sort.Ints(boundaries) idx := 0 h := hp{} for _, boundary := range boundaries { for idx < n && buildings[idx][0] <= boundary { heap.Push(&h, pair{buildings[idx][1], buildings[idx][2]}) idx++ } for len(h) > 0 && h[0].right <= boundary { heap.Pop(&h) } maxn := 0 if len(h) > 0 { maxn = h[0].height } if len(ans) == 0 || maxn != ans[len(ans)-1][1] { ans = append(ans, []int{boundary, maxn}) } } return }