2021.11.03 - 139.接雨水 II

258 篇文章 0 订阅

1. 题目

在这里插入图片描述
在这里插入图片描述

2. 思路

(1) 木桶原理+小顶堆

  • 根据木桶原理,木桶中装水的容量取决于最短的木板,因此,下标为[x,y]的方块能够接到雨水的容量取决于上下左右四个方块中接到雨水后高度最小的一个。
  • 维护一个小顶堆,存储方块的下标及其接到雨水后的高度。显然,四周的方块必然不能接到雨水,因此,先将四周方块的下标及其高度存入小顶堆中,这样就相当于在小顶堆中存储着一个围栏,不断向内缩小围栏,同时统计雨水的体积,直到围栏内不存在方块。
  • 维护一个同等大小的二维数组,标记方块是否被访问过。
  • 每次从小顶堆中弹出堆顶元素,访问其上下左右四个方向的方块,若某个方向的方块高度小于堆顶元素接到雨水后的高度,则向该方块中灌水,直到该方块的高度等于堆顶元素的高度,同时累加雨水的体积,然后缩小小顶堆中的围栏。
  • 以下图为例,将四周的围栏加入小顶堆后,弹出堆顶元素,如[0,0]的1,由于其四个方向的方块要么处于界外,要么被访问过,因此,不做任何操作,相当于该方块没有任何作用,直接排除即可。以此类推,弹出[0,3]的1,[2,5]的1,[0,5]的2,[2,0]的2,[2,3]的2。

在这里插入图片描述

  • 此时,小顶堆中维护的围栏如下图所示,再弹堆顶元素,如[0,2]的3,由于其下方的方块高度小于3,因此,向该方块中灌水,使其高度达到3,同时统计雨水的体积2,并将该方块加入小顶堆,以此缩小小顶堆中的围栏。

在这里插入图片描述

  • 此时,小顶堆中维护的围栏如下图所示,继续按照前面的规则不断弹出堆顶元素,不断缩小围栏,直到堆为空,即可得到接到雨水的总体积。

在这里插入图片描述

3. 代码

import java.util.Comparator;
import java.util.PriorityQueue;

public class Test {
    public static void main(String[] args) {
    }
}

class Solution {
    public int trapRainWater(int[][] heightMap) {
        int m = heightMap.length;
        int n = heightMap[0].length;
        PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[2] - o2[2];
            }
        });
        boolean[][] flag = new boolean[m][n];
        for (int i = 0; i < m; i++) {
            if (i == 0 || i == m - 1) {
                for (int j = 0; j < n; j++) {
                    queue.add(new int[]{i, j, heightMap[i][j]});
                    flag[i][j] = true;
                }
            } else {
                queue.add(new int[]{i, 0, heightMap[i][0]});
                flag[i][0] = true;
                queue.add(new int[]{i, n - 1, heightMap[i][n - 1]});
                flag[i][n - 1] = true;
            }
        }
        int res = 0;
        //上下左右四个方向
        int[][] dirs = new int[][]{{0, 1}, {0, -1}, {-1, 0}, {1, 0}};
        while (!queue.isEmpty()) {
            int[] poll = queue.poll();
            int h = poll[2];
            for (int[] dir : dirs) {
                int x = poll[0] + dir[0];
                int y = poll[1] + dir[1];
                if (x < 0 || x >= m || y < 0 || y >= n || flag[x][y]) {
                    continue;
                }
                if (h > heightMap[x][y]) {
                    res += (h - heightMap[x][y]);
                    queue.add(new int[]{x, y, h});
                } else {
                    queue.add(new int[]{x, y, heightMap[x][y]});
                }
                flag[x][y] = true;
            }
        }
        return res;
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值