LeetCode第407题:二维接雨水

解决二维接雨水问题的Java代码示例,并在每行添加注释以帮助你理解。

public class Solution {
    public int trapRainWater(int[][] heightMap) {
        // 如果高度图为空,或者高度图的行数或列数小于等于2,则无法接住雨水
        if (heightMap == null || heightMap.length <= 2 || heightMap[0].length <= 2) {
            return 0;
        }

        // 获取行数和列数
        int m = heightMap.length;
        int n = heightMap[0].length;

        // 使用优先队列来存储边界的单元格
        PriorityQueue<Cell> pq = new PriorityQueue<>((a, b) -> a.height - b.height);
        boolean[][] visited = new boolean[m][n];

        // 将所有边界单元格放入优先队列
        for (int i = 0; i < m; i++) {
            pq.offer(new Cell(i, 0, heightMap[i][0]));
            pq.offer(new Cell(i, n - 1, heightMap[i][n - 1]));
            visited[i][0] = true;
            visited[i][n - 1] = true;
        }
        for (int j = 1; j < n - 1; j++) {
            pq.offer(new Cell(0, j, heightMap[0][j]));
            pq.offer(new Cell(m - 1, j, heightMap[m - 1][j]));
            visited[0][j] = true;
            visited[m - 1][j] = true;
        }

        // 定义四个方向的数组
        int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
        int waterTrapped = 0;

        // 处理优先队列中的每个单元格
        while (!pq.isEmpty()) {
            Cell cell = pq.poll(); // 取出高度最低的单元格
            for (int[] dir : directions) {
                int row = cell.row + dir[0];
                int col = cell.col + dir[1];
                // 检查相邻单元格是否在边界内并且未被访问
                if (row >= 0 && row < m && col >= 0 && col < n && !visited[row][col]) {
                    // 计算当前单元格可以存储的水量
                    waterTrapped += Math.max(0, cell.height - heightMap[row][col]);
                    // 更新相邻单元格的高度为当前单元格和自身高度的最大值
                    pq.offer(new Cell(row, col, Math.max(heightMap[row][col], cell.height)));
                    visited[row][col] = true; // 标记为已访问
                }
            }
        }

        return waterTrapped; // 返回总的储水量
    }

    // 定义一个内部类来存储单元格的信息
    class Cell {
        int row, col, height;

        Cell(int row, int col, int height) {
            this.row = row;
            this.col = col;
            this.height = height;
        }
    }
}

这个代码利用优先队列(最小堆)来动态追踪当前边界的最低高度,逐步“填平”低洼区域,计算总的储水量。

解题思路

  1. 边界处理:由于水无法从边界流出,首先需要处理边界上的单元格。将所有边界单元格放入一个优先队列中(最小堆),用于动态追踪当前边界的最低高度。

  2. 优先队列(最小堆):利用优先队列从最低的高度开始处理,以确保每次处理的都是当前最低的边界。这样可以模拟水从低洼区域向高处流动的过程。

  3. 遍历和更新

    • 从优先队列中取出高度最低的单元格。
    • 检查其四个方向的相邻单元格:
      • 如果相邻单元格未访问过,计算可以存储的水量:max(0, 当前高度 - 相邻单元格高度)
      • 更新相邻单元格的高度为当前高度和自身高度的最大值(模拟水的填充)。
      • 将更新后的相邻单元格加入优先队列。
    • 标记相邻单元格为已访问。
  4. 累加水量:在遍历过程中累加可以存储的水量,最终得到总的储水量。

算法复杂度

  • 时间复杂度:O(m * n * log(m * n)),其中 m 和 n 分别是高度图的行数和列数。每个单元格最多被处理一次,且每次操作都涉及优先队列的插入和删除。
  • 空间复杂度:O(m * n),用于存储访问状态和优先队列。

总结

这个问题是对一维接雨水问题的拓展,引入了二维的高度图。通过利用优先队列,我们能够有效地处理地形的边界和低洼区域,实现动态填充水的过程。这个方法确保了每个位置的水高度是由其最低的边界决定的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值