leetcode 407. Trapping Rain Water II

本文介绍了一种解决二维地图雨水存储量计算问题的方法。通过使用优先队列维护边界单元格,逐步处理从外部到内部的单元格,确保每次处理最低高度的边界,从而收集并计算出每个单元格能存储的水量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Given an m x n matrix of positive integers representing the height of each unit cell in a 2D elevation map, compute the volume of water it is able to trap after raining.

Note:
Both m and n are less than 110. The height of each unit cell is greater than 0 and is less than 20,000.

Example:

Given the following 3x6 height map:
[
  [1,4,3,1,3,2],
  [3,2,1,3,2,4],
  [2,3,3,2,3,1]
]

Return 4.


The above image represents the elevation map [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] before the rain.


After the rain, water are trapped between the blocks. The total volume of water trapped is 4.

这道题很有思维难度。

用一个 queue 来记录当前的 border。首先,把所有位于四周 border 的格子放入队列。然后从 queue 中取出最低的格子,然后 check its neighbors:
如果它的 neighbor (设为格子A) 更低,那么收集 A 能储住的水,将 A 的高度更新为储水后的高度,然后放入队列,作为新的 border。
如果它的 neighbor 更高或等高,那么把 neighbor 放入队列,作为新的 border。

这个算法的正确性在于:每次我们只检测当前墙壁中最低高度的那个,遍历是逐步从外墙壁到内墙壁。所以当你遇到一个 neighbor 比当前 poll 出的墙高度还要低时,你一定至少能在该 neighbor 点处储住 cell.height - heights[row][col] 的水。 (remember that current cell we used are the one with the smallest height among the boarders).

package leetcode;

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

public class Trapping_Rain_Water_II_407 {

	public int trapRainWater(int[][] heightMap) {
		if(heightMap.length<=2||heightMap[0].length<=2){
			return 0;
		}
		int m=heightMap.length;
		int n=heightMap[0].length;
		int count=0;
		boolean[][] visited=new boolean[m][n];
		//queue中存储外围的墙
		PriorityQueue<Cell> queue = new PriorityQueue<Cell>(1, new Comparator<Cell>() {
			public int compare(Cell a, Cell b) {
                return a.height - b.height;
            }
		});
		
		for(int i=0;i<m;i++){
			queue.offer(new Cell(i, 0, heightMap[i][0]));
			visited[i][0]=true;
			queue.offer(new Cell(i, n-1, heightMap[i][n-1]));
			visited[i][n-1]=true;
		}
		for(int i=0;i<n;i++){
			queue.offer(new Cell(0, i, heightMap[0][i]));
			queue.offer(new Cell(m-1, i, heightMap[m-1][i]));
			visited[0][i]=true;
			visited[m-1][i]=true;
		}
		int[][] direction=new int[][]{
				{-1,0},{0,-1},{1,0},{0,1}
		};//上,左,下,右
		while(!queue.isEmpty()){
			Cell cell=queue.poll();
			for(int i=0;i<4;i++){
				int newX=cell.x+direction[i][0];
				int newY=cell.y+direction[i][1];
				if(newX<0||newX>=m||newY<0||newY>=n){
					continue;
				}
				if(!visited[newX][newY]){
					if(heightMap[newX][newY]>=heightMap[cell.x][cell.y]){
						//将它作为新的墙
						queue.offer(new Cell(newX, newY, heightMap[newX][newY]));
					}
					else{
						count+=(heightMap[cell.x][cell.y]-heightMap[newX][newY]);
						heightMap[newX][newY]=heightMap[cell.x][cell.y];
						//水坑填满水后高度设为填完水之后的高度,可以看做是墙
						queue.offer(new Cell(newX, newY, heightMap[newX][newY]));
					}
					visited[newX][newY]=true;
				}
			}
		}
		return count;
	}
	
	class Cell {
        int x;
        int y;
        int height;
        public Cell(int row, int col, int height) {
            this.x = row;
            this.y = col;
            this.height = height;
        }
    }

}
这是大神的原版解法:

Source code from:
https://github.com/shawnfan/LintCode/blob/master/Java/Trapping Rain Water II.java

public class Solution {

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

    public int trapRainWater(int[][] heights) {
        if (heights == null || heights.length == 0 || heights[0].length == 0)
            return 0;

        PriorityQueue<Cell> queue = new PriorityQueue<>(1, new Comparator<Cell>(){
            public int compare(Cell a, Cell b) {
                return a.height - b.height;
            }
        });
        
        int m = heights.length;
        int n = heights[0].length;
        boolean[][] visited = new boolean[m][n];

        // Initially, add all the Cells which are on borders to the queue.
        for (int i = 0; i < m; i++) {
            visited[i][0] = true;
            visited[i][n - 1] = true;
            queue.offer(new Cell(i, 0, heights[i][0]));
            queue.offer(new Cell(i, n - 1, heights[i][n - 1]));
        }

        for (int i = 0; i < n; i++) {
            visited[0][i] = true;
            visited[m - 1][i] = true;
            queue.offer(new Cell(0, i, heights[0][i]));
            queue.offer(new Cell(m - 1, i, heights[m - 1][i]));
        }

        // from the borders, pick the shortest cell visited and check its neighbors:
        // if the neighbor is shorter, collect the water it can trap and update its height as its height plus the water trapped
       // add all its neighbors to the queue.
        int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        int res = 0;
        while (!queue.isEmpty()) {
            Cell cell = queue.poll();
            for (int[] dir : dirs) {
                int row = cell.row + dir[0];
                int col = cell.col + dir[1];
                if (row >= 0 && row < m && col >= 0 && col < n && !visited[row][col]) {
                    visited[row][col] = true;
                    res += Math.max(0, cell.height - heights[row][col]);
                    queue.offer(new Cell(row, col, Math.max(heights[row][col], cell.height)));
                }
            }
        }
        
        return res;
    }
}
还有大神说可以看看youtube上的动态图解视频来直观地了解解法,但是貌似那个解法不是上面的解法?

总之有兴趣可以看看(要搭梯子),网址:https://www.youtube.com/watch?v=cJayBq38VYw

我截了点图,顺序是一层层从左往右看。可以点开链接看清晰大图。https://img-blog.youkuaiyun.com/20170830170703057



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值