Trapping Rain Water II
Advertisement
Problem
Given an m×n height matrix, compute total water trapped in 3D.
Key insight: BFS outward from borders using min-heap. The minimum border height is the water level. Process inward cells: water trapped = max(0, current_water_level - cell_height). Update water level.
Solutions
// C++
int trapRainWater(vector<vector<int>>& heightMap) {
int m=heightMap.size(), n=heightMap[0].size();
if (m<3||n<3) return 0;
vector<vector<bool>> vis(m, vector<bool>(n, false));
priority_queue<tuple<int,int,int>, vector<tuple<int,int,int>>, greater<>> minH;
for (int i=0;i<m;i++) for(int j=0;j<n;j++) if(i==0||i==m-1||j==0||j==n-1){minH.push({heightMap[i][j],i,j});vis[i][j]=true;}
int res=0;
int dx[]={0,0,1,-1}, dy[]={1,-1,0,0};
while (!minH.empty()) {
auto [h,r,c] = minH.top(); minH.pop();
for (int d=0;d<4;d++) {
int nr=r+dx[d], nc=c+dy[d];
if (nr<0||nr>=m||nc<0||nc>=n||vis[nr][nc]) continue;
vis[nr][nc]=true;
res += max(0, h-heightMap[nr][nc]);
minH.push({max(h,heightMap[nr][nc]),nr,nc});
}
}
return res;
}
// Java
public int trapRainWater(int[][] heightMap) {
int m=heightMap.length, n=heightMap[0].length;
if (m<3||n<3) return 0;
boolean[][] vis = new boolean[m][n];
PriorityQueue<int[]> minH = new PriorityQueue<>(Comparator.comparingInt(a->a[0]));
for(int i=0;i<m;i++) for(int j=0;j<n;j++) if(i==0||i==m-1||j==0||j==n-1){minH.offer(new int[]{heightMap[i][j],i,j});vis[i][j]=true;}
int res=0;
int[]dx={0,0,1,-1},dy={1,-1,0,0};
while(!minH.isEmpty()){
int[]p=minH.poll();
for(int d=0;d<4;d++){
int nr=p[1]+dx[d],nc=p[2]+dy[d];
if(nr<0||nr>=m||nc<0||nc>=n||vis[nr][nc])continue;
vis[nr][nc]=true;
res+=Math.max(0,p[0]-heightMap[nr][nc]);
minH.offer(new int[]{Math.max(p[0],heightMap[nr][nc]),nr,nc});
}
}
return res;
}
# Python
import heapq
def trapRainWater(heightMap):
if not heightMap or len(heightMap) < 3 or len(heightMap[0]) < 3:
return 0
m, n = len(heightMap), len(heightMap[0])
visited = [[False] * n for _ in range(m)]
heap = []
for i in range(m):
for j in range(n):
if i == 0 or i == m-1 or j == 0 or j == n-1:
heapq.heappush(heap, (heightMap[i][j], i, j))
visited[i][j] = True
result = 0
while heap:
h, r, c = heapq.heappop(heap)
for dr, dc in [(0,1),(0,-1),(1,0),(-1,0)]:
nr, nc = r + dr, c + dc
if 0 <= nr < m and 0 <= nc < n and not visited[nr][nc]:
visited[nr][nc] = True
result += max(0, h - heightMap[nr][nc])
heapq.heappush(heap, (max(h, heightMap[nr][nc]), nr, nc))
return result
// JavaScript
function trapRainWater(heightMap) {
const m = heightMap.length, n = heightMap[0].length;
if (m < 3 || n < 3) return 0;
// Use sorted array as min-heap substitute
const vis = Array.from({length: m}, () => Array(n).fill(false));
const heap = [];
for (let i = 0; i < m; i++) for (let j = 0; j < n; j++) {
if (i === 0 || i === m-1 || j === 0 || j === n-1) {
heap.push([heightMap[i][j], i, j]); vis[i][j] = true;
}
}
heap.sort((a, b) => a[0] - b[0]);
let result = 0;
const dirs = [[0,1],[0,-1],[1,0],[-1,0]];
while (heap.length) {
const [h, r, c] = heap.shift();
for (const [dr, dc] of dirs) {
const nr = r+dr, nc = c+dc;
if (nr < 0 || nr >= m || nc < 0 || nc >= n || vis[nr][nc]) continue;
vis[nr][nc] = true;
result += Math.max(0, h - heightMap[nr][nc]);
const nh = Math.max(h, heightMap[nr][nc]);
let pos = heap.findIndex(x => x[0] >= nh);
if (pos === -1) heap.push([nh, nr, nc]);
else heap.splice(pos, 0, [nh, nr, nc]);
}
}
return result;
}
Complexity
- Time: O(mn log(mn))
- Space: O(m*n)
Key Insight
The minimum border height becomes the "water level" for interior cells. Process cells in order of their water boundary height — always expand from the weakest boundary.
Advertisement
← Previous
Swim in Rising Water