【扫描线】LeetCode 218. 天际线问题

题目链接

218. 天际线问题

思路

参考宫水三叶大佬题解

image

求最大值

观察上面的图可以发现,我们需要求的其实就只是一个一个小矩形,做的其实相当于一个矩阵分割。并且求得还得是每一段的最大高度。

那么在不断变化的各种数值之间求最大数值,很容易想到使用优先队列,这样在动态的过程中始终能找到最大值。

接下来就是如何遍历的问题了。

排序

扫描线问题遍历的一个基本思路是将左右两个端点进行拆分,再进行遍历。

什么意思呢?

比如说题目中的格式是 \(\{r_i, l_i, h_i\}\),那么我们需要拆分成 \(\{l_i, h_i\}\)\(\{r_i, h_i\}\)

因为要从左到右进行遍历,所以需要按坐标对所有的建筑进行排序,如果两个建筑有坐标重合了,便让左边的建筑物排前面,右边的排后面。

为了方便区分左右端点,我们将本应拆分成的 \(\{l_i, h_i\}\) 变为 \(\{l_i, -h_i\}\)。这样在坐标相等的时候,只需要再对高度进行一个从小到大排序就行了。

遍历

经过上面的排序预处理,我们可以从左到右排序,遇到左端点就将高度加入队列,遇到右端点就将高度移除队列。

每遍历一个节点都需要判断一下堆顶有没有变化,可以使用单边量 prev 记录遍历上一个节点后的堆顶值。如果有变化则进行记录。

这时候又会遇到一个问题,还是看上面的图

image

在 10 到 15 之间有一小段空白,这也意味着在绿色建筑出队之后,队列为空,还需要对堆为空进行一个特判。那怎么节省这段特判呢?

有一个小技巧是将空白视为高度为0的建筑,这样相当于在队列中永远有一个数值 0 来兜底,保证队列不为空,也就不需要特判了。

代码

class Solution {
    public List<List<Integer>> getSkyline(int[][] buildings) {
        List<List<Integer>> result = new ArrayList<>();
        List<int[]> path = new ArrayList<>();

        for(int[] building : buildings){
            int left = building[0];
            int right = building[1];
            int height = building[2];

            // 方便排序,让左端点高度为负数;同时能识别当前点为左端点还是右端点
            path.add(new int[]{left, -height});
            path.add(new int[]{right, height});
        }

        Collections.sort(path, (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);
        int prev = 0;
        queue.add(prev);

        for(int i = 0; i < path.size(); i++){
            int[] temp = path.get(i);
            // 如果小于0,说明是左端点,需要入队
            if(temp[1] < 0){
                queue.add(-temp[1]);
            }else{
                queue.remove(temp[1]);
            }

            int current = queue.peek();
            if(current != prev){
                prev = current;
                result.add(Arrays.asList(new Integer[]{temp[0], current}));
            }
        }

        return result;
    }
}
posted @ 2023-04-13 10:32  Frodo1124  阅读(26)  评论(0编辑  收藏  举报