題目描述
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.
求出凹陷下去的地方能盛的水體積
解題思路
雖然是bfs的標籤,但是因爲第一次接觸這種類型題,完全無思路(畢竟是hard),然後,發現了一位大神圖文並茂的解題說明(感激!):
Grandyang的博客(我只是參考瞭解題思路,代碼是自己寫的)
一個方塊能裝水,那麼它的四周都必須是比它高的方塊,因此,bfs的應用就是,取出一個方塊,遍歷它外圍的四塊方塊。然而,題目並不是那麼簡單。這道題還用到了優先隊列(每次挑選高度最小的出隊,和一般的bfs不一樣,優先隊列參考內容:ZXH小朋友的上學史 的博客)以及模擬海平面上升的方法(Grandyang 博客裏有):海平面初始值爲1,取出priorityqueue的top元素,若是 高度 > 海平面,則用這個值更新海平面,遍歷元素四周的方塊,低於海平面,則可裝的水是海平面 - 方塊高度。
好了,現在對整個解題過程進行總結:
一、主要準備:
1、priority queue (forBFS):裝有最外圍一圈方塊,並以高度從小到大出隊。
2、海平面(seaRevel):方塊裝水的參照,裝水量:海平面 - 方塊高度
3、代表元素座標、高度的box
4、代表box四周方塊的座標偏移量pos{(1,0),(0,1),(-1,0),(0,-1)}(要注意越界問題)
二、核心思路:
出隊一個box,判斷四周方塊是否被訪問過,如果沒有,把方塊入隊,置visited = true。判斷遍歷的方塊與海平面的關係,能裝的水:海平面 - 方塊高度。
代碼如下:
class Solution {
public:
struct Box {
int x;
int y;
int height;
Box(int a, int b, int c) :x(a), y(b), height(c) {
}
bool operator < (const Box& b) const {
return b.height < height;
}
};
int trapRainWater(vector<vector<int>>& heightMap) {
if (heightMap.size() == 0) {
return 0;
}
int rowCount = heightMap.size();
int colCount = heightMap[0].size();
priority_queue<Box> forBFS;
vector<bool> tmp(colCount, false);
vector<vector<bool> >visited(rowCount, tmp);
for (int i = 0; i < colCount; i++) {
if (!visited[0][i]) {
forBFS.push(Box(0, i, heightMap[0][i]));
visited[0][i] = true;
}
if (!visited[rowCount - 1][i]) {
forBFS.push(Box(rowCount - 1, i, heightMap[rowCount - 1][i]));
visited[rowCount - 1][i] = true;
}
}
for (int j = 0; j < rowCount; j++) {
if (!visited[j][0]) {
forBFS.push(Box(j, 0, heightMap[j][0]));
visited[j][0] = true;
}
if (!visited[j][colCount - 1]) {
forBFS.push(Box(j, colCount - 1, heightMap[j][colCount - 1]));
visited[j][colCount - 1] = true;
}
}
int seaRevel = 0;
int water = 0;
vector<pair<int, int> > pos;
pos.push_back(pair<int, int>(0, 1));
pos.push_back(pair<int, int>(1, 0));
pos.push_back(pair<int, int>(0, -1));
pos.push_back(pair<int, int>(-1, 0));
while (!forBFS.empty()) {
Box now = forBFS.top();
forBFS.pop();
if (seaRevel < now.height)
seaRevel = now.height;
for (int i = 0; i < 4; i++) {
pair<int, int> next = pos[i];
int nextX = now.x + next.first;
int nextY = now.y + next.second;
if (nextX < 0 || nextY < 0)
continue;
if (nextX >= rowCount || nextY >= colCount)
continue;
if (!visited[nextX][nextY]) {
water = seaRevel > heightMap[nextX][nextY] ? water + (seaRevel - heightMap[nextX][nextY]) : water + 0;
forBFS.push(Box(nextX, nextY, heightMap[nextX][nextY]));
visited[nextX][nextY] = true;
}
}
}
return water;
}
};
感觸:
1、優先隊列的使用
2、vector的初始化方法,vector(numberOfElements,value),省去了memset的調用
3、bfs的應用(我覺得也是這道題的難點)