https://leetcode.com/problems/trapping-rain-water-ii/description/
感谢室友在思路上的提点
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.
要求坑里的水,首先得知道哪些是坑,可以知道的是边缘的一定不是坑,水一定会在边缘处流出,然后边缘临近的位置假如比边缘高,那么这个位置的水就会留到边缘处,然后流出去,所以这个位置成为了新的边缘。
那么最简单的方法就是先从边缘开始都广搜一波,标记边缘,那么这个图就会收缩,没有被标记到的就是我们的水坑,然后统计这里的水量,这里就需要再次广搜以确定每个坑的最低的边缘高度,然后结合原图就能统计完成了,思路很简单很暴力。
换个角度看,能不能在收缩的时候把坑的最低边缘高度确定下来?可以确定的是,水一定是从最低的边缘流出来的,假如我们知道每个边缘的最低高度low,假如附近没坑,那么水就是这里流出来,假如有坑ij,那么坑一定会被填满,填的水量就是low.height-heightMap[i][j]
,然后这个被填满的坑不就成为了新的边缘了吗?这样我们得出了新的收缩方式,不再是单纯去确定是不是坑,而是在收缩的过程中,把坑填满当作边缘就好了。也就是重复寻找边缘中的最小值然后收缩附近一格,是坑就填成边缘,不是就直接当作边缘。最小堆就能实现快速找最小,所以用个优先队列。
class Solution {
public:
int trapRainWater(vector<vector<int>>& heightMap) {
int n = heightMap.size();
if (n == 0) return 0;
int m = heightMap[0].size();
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> que;
int visit[n+1][m+1] = {0}; // 标记过的都是边缘
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (i == 0 || j == 0 || i == n-1 || j == m-1) {
que.push(make_pair(heightMap[i][j], i * m + j));
visit[i][j] = 1;
}
}
}
int dx[4] = {-1,1,0,0};
int dy[4] = {0,0,-1,1};
int res = 0;
while (!que.empty()) {
pair<int, int> low = que.top(); que.pop();
int i = low.second / m;
int j = low.second % m;
// 四个方向收缩一格
for (int k = 0; k < 4; ++k) {
int ii = i + dx[k];
int jj = j + dy[k];
if (ii > 0 && ii < n && jj > 0 && jj < m && !visit[ii][jj]) {
visit[ii][jj] = 1;
// 大于则是坑
if (low.first > heightMap[ii][jj])
res += low.first - heightMap[ii][jj];
// max就是填坑做边缘或者非坑直接做边缘
que.push(make_pair(max(low.first, heightMap[ii][jj]), ii * m + jj));
}
}
}
return res;
}
};