题目链接
天际线问题
题目描述
注意点
- 可以假设所有的建筑都是完美的长方形,在高度为 0 的绝对平坦的表面上
- 输出天际线中不得有连续的相同高度的水平线
- buildings 按 lefti 非递减排序
解答思路
- 矩形会有重叠部分,当多个矩形重合时,取高度最高的矩形,如示例一中的图B所示,本题关键是要找到转换为图B后的每个矩形的左侧端点及高度
- 参考题解使用扫描线+优先队列解决,扫描线使用竖线,将初始每个矩阵的左右端点使用扫描线标记,为了方便后续排序,将左端点对应的高度设置为负数,后续排序的规则为:左端点比右端点优先,如果都是左端点/右端点,则将高度更高的端点优先,保证按顺序遍历扫描线,同时如果多个矩形的扫描线重合时更高的矩形也能包住更低的矩形
- 随后使用优先队列找到关键点,在访问到左端点时入栈,访问到右端点时其对应的矩形已到尽头,需要出栈,优先队列始终保证队首的元素为当前所有覆盖的矩形中的最高高度,如果最高高度相比上一次关键点发生了变化,则需要将当前的关键点加入到结果集中,并更新上一次关键点为当前关键点
代码
class Solution {
public List<List<Integer>> getSkyline(int[][] bs) {
List<List<Integer>> res = new ArrayList<>();
int n = bs.length;
List<int[]> xyList = new ArrayList<>(n * 2);
for (int i = 0; i < n; i++) {
int left = bs[i][0];
int right = bs[i][1];
int height = bs[i][2];
int[] leftPoint = {left, -height};
int[] rightPoint = {right, height};
xyList.add(leftPoint);
xyList.add(rightPoint);
}
Collections.sort(xyList, (a, b) -> {
if (a[0] != b[0]) {
return a[0] - b[0];
}
return a[1] - b[1];
});
PriorityQueue<Integer> queue = new PriorityQueue<>((a, b) -> (b - a));
queue.add(0);
int prevHeight = 0;
for (int[] point : xyList) {
int x = point[0];
int y = point[1];
if (y < 0) {
queue.add(-y);
} else {
queue.remove(y);
}
int maxHeight = queue.peek();
if (prevHeight != maxHeight) {
List<Integer> sonRes = new ArrayList<>(2);
sonRes.add(x);
sonRes.add(maxHeight);
res.add(sonRes);
prevHeight = maxHeight;
}
}
return res;
}
}
关键点
- 扫描线的思想(本题存储二元数组(x, y),x为横坐标值,y为纵坐标值,也是高度)
- 优先队列的使用
- 将左端点的高度都设置为负数保证左端点始终优先于右端点