[LeetCode] 407. Trapping Rain Water II 收集雨水之二

 

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.html

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. git

Example: github

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. app

 

这道题是以前那道 Trapping Rain Water 的拓展,由 2D 变 3D 了,感受很叼。但其实解法跟以前的彻底不一样了,以前那道题因为是二维的,咱们能够用双指针来作,而这道三维的,咱们须要用 BFS 来作,解法思路很巧妙,下面咱们就以题目中的例子来进行分析讲解,多图预警,手机流量党慎入:less

首先咱们应该能分析出,能装水的底面确定不能在边界上,由于边界上的点没法封闭,那么全部边界上的点均可以加入 queue,看成 BFS 的启动点,同时咱们须要一个二维数组来标记访问过的点,访问过的点咱们用红色来表示,那么以下图所示:post

 

 

咱们再想一想,怎么样能够成功的装进去水呢,是否是周围的高度都应该比当前的高度高,造成一个凹槽才能装水,并且装水量取决于周围最小的那个高度,有点像木桶原理的感受,那么为了模拟这种方法,咱们采用模拟海平面上升的方法来作,咱们维护一个海平面高度 mx,初始化为最小值,从1开始往上升,那么咱们 BFS 遍历的时候就须要从高度最小的格子开始遍历,那么咱们的 queue 就不能使用普通队列了,而是使用优先级队列,将高度小的放在队首,最早取出,这样咱们就能够遍历高度为1的三个格子,用绿色标记出来了,以下图所示:url

 

 

如上图所示,向周围 BFS 搜索的条件是不能越界,且周围格子未被访问,那么能够看出上面的第一个和最后一个绿格子没法进一步搜索,只有第一行中间那个绿格子能够搜索,其周围有一个灰格子未被访问过,将其加入优先队列 queue 中,而后标记为红色,以下图所示:spa

 

 

那么优先队列 queue 中高度为1的格子遍历完了,此时海平面上升1,变为2,此时咱们遍历优先队列 queue 中高度为2的格子,有3个,以下图绿色标记所示:3d

 

 

咱们发现这三个绿格子周围的格子均已被访问过了,因此不作任何操做,海平面继续上升,变为3,遍历全部高度为3的格子,以下图绿色标记所示:

 

 

因为咱们没有特别声明高度相同的格子在优先队列 queue 中的顺序,因此应该是随机的,其实谁先遍历到都同样,对结果没啥影响,咱们就假设第一行的两个绿格子先遍历到,那么那么周围各有一个灰格子能够遍历,这两个灰格子比海平面低了,能够存水了,把存水量算出来加入结果 res 中,以下图所示:

 

 

上图中这两个遍历到的蓝格子会被加入优先队列 queue 中,因为它们的高度小,因此下一次从优先队列 queue 中取格子时,它们会被优先遍历到,那么左边的那个蓝格子进行BFS搜索,就会遍历到其左边的那个灰格子,因为其高度小于海平面,也能够存水,将存水量算出来加入结果 res 中,以下图所示:

 

 

等两个绿格子遍历结束了,它们会被标记为红色,蓝格子遍历会先被标记红色,而后加入优先队列 queue 中,因为其周围格子全变成红色了,全部不会有任何操做,以下图所示:

 

 

此时全部的格子都标记为红色了,海平面继续上升,继续遍历完优先队列 queue 中的格子,不过已经不会对结果有任何影响了,由于全部的格子都已经访问过了,此时等循环结束后返回res便可,参见代码以下:

 

class Solution {
public:
    int trapRainWater(vector<vector<int>>& heightMap) {
        if (heightMap.empty()) return 0;
        int m = heightMap.size(), n = heightMap[0].size(), res = 0, mx = INT_MIN;
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> q;
        vector<vector<bool>> visited(m, vector<bool>(n, false));
        vector<vector<int>> dir{{0,-1},{-1,0},{0,1},{1,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) {
                    q.push({heightMap[i][j], i * n + j});
                    visited[i][j] = true;
                }
            }
        }
        while (!q.empty()) {
            auto t = q.top(); q.pop();
            int h = t.first, r = t.second / n, c = t.second % n;
            mx = max(mx, h);
            for (int i = 0; i < dir.size(); ++i) {
                int x = r + dir[i][0], y = c + dir[i][1];
                if (x < 0 || x >= m || y < 0 || y >= n || visited[x][y]) continue;
                visited[x][y] = true;
                if (heightMap[x][y] < mx) res += mx - heightMap[x][y];
                q.push({heightMap[x][y], x * n + y});
            }
        }
        return res;
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/407

 

相似题目:

Trapping Rain Water

 

参考资料:

https://leetcode.com/problems/trapping-rain-water-ii/

https://leetcode.com/problems/trapping-rain-water-ii/discuss/89461/Java-solution-using-PriorityQueue

https://leetcode.com/problems/trapping-rain-water-ii/discuss/89476/concise-C%2B%2B-priority_queue-solution

 

LeetCode All in One 题目讲解汇总(持续更新中...)

相关文章
相关标签/搜索