題目鏈接:https://leetcode.com/problems/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.
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
思路:如果做過這題I的應該知道,在第一題中基本思路是每次從兩端的高度較小的一端移動,這樣做的意義在於我們每次都是遍歷最短的一個位置,也就是根據木桶原理這裏最可能漏水,還需要維護一個當前邊界的最大值.這樣如果如果某一個高度小於當前維護的邊界最大值,那麼這裏就可以保存一些水.
二維的原理和一維的思路基本是一樣的.在一維中我們只需從兩個端點選一個即可,而在二維中可選的點就擴大成了整個矩形的邊.根據上一題知道我們同樣每次應該先選取邊界最小的高度,所以很自然的可以想到應該用優先隊列來保存周圍邊界(小頂堆).在我們訪問過了一個點之後要繼續往矩形內部遍歷,這樣還需要保存一個點的位置.爲了防止再次訪問已經訪問過的點還需要用一個數組來標記每個點的訪問狀態.
時間複雜度應該是O(m*n*log(m+n)).
代碼如下:
class Solution {
public:
int trapRainWater(vector<vector<int>>& heightMap) {
if(heightMap.size()==0) return 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> que;
int row = heightMap.size(), col = heightMap[0].size();
vector<vector<int>> visited(row, vector<int>(col, 0));
int ans = 0, Max = INT_MIN;
for(int i = 0; i < row; i++)
{
for(int j = 0; j < col; j++)
{
if(!(i==0 || i==row-1 || j==0 || j==col-1)) continue;
que.push(make_pair(heightMap[i][j], i*col+j));
visited[i][j] = 1;
}
}
vector<vector<int>> dir{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
while(!que.empty())
{
auto val = que.top(); que.pop();
int height = val.first, x = val.second/col, y = val.second%col;
Max = max(Max, height);
for(auto d: dir)
{
int x2 = x + d[0], y2 = y + d[1];
if(x2>=row || x2<0 || y2<0 || y2>=col || visited[x2][y2]) continue;
visited[x2][y2] = 1;
if(heightMap[x2][y2] < Max) ans += Max - heightMap[x2][y2];
que.push(make_pair(heightMap[x2][y2], x2*col+y2));
}
}
return ans;
}
};