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.
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.
接雨水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(m * n * log(m + n)) - 有两个for loop所以起码是mn,同时pq一开始加入了2m + 2n个元素,每次都是2m + 2n个元素及其四维的元素之间找最小值
空间O(mn)
Java实现
1 class Solution { 2 public int trapRainWater(int[][] heightMap) { 3 // corner case 4 if (heightMap == null || heightMap.length <= 1 || heightMap[0].length <= 1) { 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 if (i == 0 || j == 0 || i == m - 1 || j == n - 1) { 16 visited[i][j] = true; 17 pq.offer(new int[] { i, j, heightMap[i][j] }); 18 } 19 } 20 } 21 22 int res = 0; 23 int[][] dirs = new int[][] { { -1, 0 }, { 1, 0 }, { 0, 1 }, { 0, -1 } }; 24 while (!pq.isEmpty()) { 25 int[] cell = pq.poll(); 26 for (int[] dir : dirs) { 27 int x = cell[0] + dir[0]; 28 int y = cell[1] + dir[1]; 29 if (x >= 0 && x < m && y >= 0 && y < n && !visited[x][y]) { 30 visited[x][y] = true; 31 res += Math.max(0, cell[2] - heightMap[x][y]); 32 pq.offer(new int[] { x, y, Math.max(cell[2], heightMap[x][y]) }); 33 } 34 } 35 } 36 return res; 37 } 38 }