05 August 2008
Given an
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.1
m x n
Example:
1
2
3
4
5
6
7
8
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
before the rain.1
[[1,4,3,1,3,2],[3,2,1,3,2,4],[2,3,3,2,3,1]]
After the rain, water is trapped between the blocks. The total volume of water trapped is 4.
Constraints:
1
1 <= m, n <= 110
1
0 <= heightMap[i][j] <= 20000
第42题是1-D的接雨水问题,其中的DP解法是从左右两边的边界往中间进行收缩,收缩的过程中,对每个坐标(一维坐标)头顶上能接的雨水进行累加。
这道题是2-D的接雨水的问题,这个边界不再是线段的两个端点,而是矩形的一周,所以用优先队列维护所有边界点,收缩时,也不仅仅只有左右两个方向,而是上下左右四个方向,分别计算柱子头顶对比四周可以存储的雨水,同时维护一个visit的数组,记录哪些坐标已经被访问过,不然会造成重复求解。因此,这是个PQ+BFS的解法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class Solution {
/**
维护一个Cell类来hold一根柱子的横纵坐标和高度
*/
class Cell {
private int row;
private int col;
private int height;
public Cell(int row, int col, int height) {
this.row = row;
this.col = col;
this.height = height;
}
}
public int trapRainWater(int[][] heightMap) {
int result = 0;
if (heightMap == null || heightMap.length == 0 || heightMap[0].length == 0) {
return result;
}
int m = heightMap.length;
int n = heightMap[0].length;
PriorityQueue<Cell> pq = new PriorityQueue<>(Comparator.comparingInt((Cell cell) -> cell.height)); // 优先队列的顺序从最高的柱子开始检查
boolean[][] visited = new boolean[m][n];
// 首先把二维数组的四个边加入到pq中,准备往中间计算
for (int k = 0; k < m; k++) {
visited[k][0] = true;
pq.offer(new Cell(k, 0, heightMap[k][0]));
visited[k][n - 1] = true;
pq.offer(new Cell(k, n - 1, heightMap[k][n - 1]));
}
for (int k = 1; k < n - 1; k++) { // 左上和右下两个点已经处理
visited[0][k] = true;
pq.offer(new Cell(0, k, heightMap[0][k]));
visited[m - 1][k] = true;
pq.offer(new Cell(m - 1, k, heightMap[m - 1][k]));
}
int[][] dirs = { {1, 0},{-1, 0},{0, 1},{0, -1} };
while (!pq.isEmpty()) {
// 与BFS的标准写法不同的一点是,这个BFS不用计算扩散中每一层有多少个元素
Cell oneCell = pq.poll();
for (int[] dir : dirs) {//当前柱子的四个方向
int newX = oneCell.row + dir[0];
int newY = oneCell.col + dir[1];
if (newX >= 0 && newX < m && newY >= 0 && newY < n && !visited[newX][newY]) {
result += Math.max(0, oneCell.height - heightMap[newX][newY]); // 当前柱子与周边四个柱子比较,水往低处流
pq.offer(new Cell(newX, newY, Math.max(oneCell.height, heightMap[newX][newY]))); //选择height的时候需要选较高的柱子,水流不过去
visited[newX][newY] = true;
}
}
}
return result;
}
}