[LeetCode] 407. Trapping Rain Water II
Given an m x n
integer matrix heightMap
representing the height of each unit cell in a 2D elevation map, return the volume of water it can trap after raining.
Example 1:
Input: heightMap = [[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]] Output: 4 Explanation: After the rain, water is trapped between the blocks. We have two small ponds 1 and 3 units trapped. The total volume of water trapped is 4.
Example 2:
Input: heightMap = [[3,3,3,3,3],[3,2,2,2,3],[3,2,1,2,3],[3,2,2,2,3],[3,3,3,3,3]] Output: 10
Constraints:
m == heightMap.length
n == heightMap[i].length
1 <= m, n <= 200
0 <= heightMap[i][j] <= 2 * 104
接雨水II。
给你一个 m x n
的矩阵,其中的值均为非负整数,代表二维高度图每个单元的高度,请计算图中形状最多能接多少体积的雨水。
题意跟版本一很像,但是这个题改成三维的了。思路是BFS + priority queue,同时需要一个跟input数组一样大的二维数组visited,记录每个坐标是否被遍历过。里面细节很多,具体讲一讲。
因为这个题是立体的,所以首先发现的是二维数组的最外面一圈的数字是只能当做墙壁不能盛水的。所以此时将他们加入 pq,加入的时候存(横坐标x,纵坐标y,坐标值height)。pq 是按坐标值 height 排序的一个最小堆,意思是坐标值 height 最小的元素会优先被 pop 出来。pop 出来的时候,扫描这个坐标的四个方向上的没有被 visited 过的坐标,看他们之间的高度差是否有可能大于 0。换言之,每次弹出来的坐标,你把当前坐标当做一堵墙,看他是否比自己的四个邻居的高度要高,如果是,当前这个坐标就能为他自己的四个邻居坐标盛水。盛水的原则就是当前坐标的高度 cell[2] 比他的邻居坐标的高度 heightMap[x][y] 要高。这个跟版本一很像,无非是版本一只是看左右两个方向,这个题这里是看四个方向。在看四个方向的时候,记得跳过已经访问过的坐标和超出矩阵范围外的坐标。其余的部分就是 BFS 的套路了。
核心思想就是先确定木桶的外围,找到外围的最短板子后对其周围能填水的地方填水,然后更新木桶外围。
时间
空间O(mn)
Java实现
1 class Solution { 2 public int trapRainWater(int[][] heightMap) { 3 // corner case 4 if (heightMap == null || heightMap.length == 0) { 5 return 0; 6 } 7 8 // normal case 9 int m = heightMap.length; 10 int n = heightMap[0].length; 11 boolean[][] visited = new boolean[m][n]; 12 PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[2] - b[2]); 13 for (int i = 0; i < m; i++) { 14 for (int j = 0; j < n; j++) { 15 // 把矩阵边缘上的点加入pq 16 if (i == 0 || j == 0 || i == m - 1 || j == n - 1) { 17 visited[i][j] = true; 18 pq.offer(new int[] { i, j, heightMap[i][j] }); 19 } 20 } 21 } 22 23 int res = 0; 24 int[][] dirs = new int[][] { { -1, 0 }, { 1, 0 }, { 0, 1 }, { 0, -1 } }; 25 while (!pq.isEmpty()) { 26 int[] cell = pq.poll(); 27 for (int[] dir : dirs) { 28 int x = cell[0] + dir[0]; 29 int y = cell[1] + dir[1]; 30 // 某个点被弹出后,如果他的邻居节点在矩阵范围内同时没有被访问过我们才计算高度差 31 // 这样我们就隐性地跳过了一开始加入pq的那些在矩阵边缘上的点 32 if (x >= 0 && x < m && y >= 0 && y < n && !visited[x][y]) { 33 visited[x][y] = true; 34 // res += Math.max(0, cell[2] - heightMap[x][y]); 35 if (cell[2] > heightMap[x][y]) { 36 res += cell[2] - heightMap[x][y]; 37 } 38 // 将这个邻居的高度更新成Math.max(cell[2], heightMap[x][y]) 39 // 相当于是墙就是这个高度了或者是已经可以装水装到这个高度了 40 pq.offer(new int[] { x, y, Math.max(cell[2], heightMap[x][y]) }); 41 } 42 } 43 } 44 return res; 45 } 46 }