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
相似題目:
參考資料:
https://leetcode.com/problems/trapping-rain-water-ii/
https://leetcode.com/problems/trapping-rain-water-ii/discuss/89461/Java-solution-using-PriorityQueue