Leetcode 407. Trapping Rain Water II

来源:互联网 发布:黄金分析软件怎么样? 编辑:程序博客网 时间:2024/05/16 05:11

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;    }};
原创粉丝点击