[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 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索