leetcode中的接雨水問題
從2D到3D,考察的知識點完全不同:2D中要求掌握雙指針算法技巧,3D中要求掌握廣度優先搜索算法+優先隊列使用技巧
針對這個3D接雨水問題,羅列知識點
BFS:
廣度優先搜索算法
breadth first search / broad first search
DFS:
深度優先搜索算法
deep first search
數據結構——圖的遍歷算法,根據訪問節點的順序,分爲廣度優先搜索BFS和深度優先搜索DFS。
- 什麼是圖?一種靈活的數據結構,一般作爲一種模型用來定義對象之間的關係或聯繫。
- 圖的表示:對象由頂點(V)表示,而對象之間的關係或者關聯則通過圖的邊(E)來表示。 圖可以分爲有向圖和無向圖,一般用G=(V,E)來表示圖。經常用鄰接矩陣或者鄰接表來描述一副圖。
廣度優先搜索BFS
// 通常用隊列(先進先出,FIFO)實現
// 初始化隊列Q
Q={起點s};
標記s爲已訪問;
while(Q非空){
取QQ隊首元素u;
u出隊;
if(u==目標狀態){
...
}
所有與u相鄰且未被訪問的點進入隊列;
標記u爲已訪問;
}
使用隊列保存未被檢測的結點。結點按照寬度有限的次序被訪問和進出隊列。
--類似於樹的按層次遍歷的過程
--廣搜例子:你的眼鏡掉在地上之後,你趴在地板上找。你總是先摸最接近你的地方,如果沒有,再摸遠一點的地方……
BFS算法用到了優先級隊列,注意隊列中元素的比較操作重載!
深度優先搜索DFS
思想:一直往深處走,直到找到接或者走不下去爲止
DFS(dep,...) //dep代表目前DFS的深度
{
if(找到解||走不下去了)
{
...
return;
}
枚舉下一種情況,DFS(dep+1,...)
}
使用棧保存未被檢測的結點,結點按照深度優先的次序被訪問並以此被壓入棧中,並以相反的次序出棧進行新的檢測。
--類似於樹的先根遍歷
--深搜例子:走迷宮,你沒有辦法用分身術來站在每個走過的位置。不撞南牆不回頭。
DFS算法用到了遞歸和回溯。
實際案例:
BFS在三維接雨水問題中的應用。
問題來源與描述:https://leetcode-cn.com/problems/trapping-rain-water-ii/
輔助理解參考:https://blog.csdn.net/weixin_42054167/article/details/91989108
解法:
struct RainNode {
int i, j, h;
RainNode(int ii, int jj, int hh) :i(ii), j(jj), h(hh) {}
bool operator <(const RainNode& root) const {
return h>root.h;
}
};
int trapRainWater(vector<vector<int>>& heightMap) {
if (heightMap.empty()) return 0;
int m = heightMap.size(), n = heightMap[0].size();
int area = 0, h = 0; //h模擬水池外的海平面上升,m*n矩陣可以看做一個可以蓄水的水池
// 存放訪問過的格子,且每次執行時刪除高度最小的格子
// 存放的過程中,會將當前最小高度的幾個格子放在前幾個位置(後面的並不按順序排放)
priority_queue<RainNode> q; //優先級隊列,該隊列中是將高度小的放在隊首
vector<vector<bool>> visit(m, vector<bool>(n, false)); //m*n矩陣記錄高度塊是否被訪問過
// 最外圍的高度塊是不可能蓄水的,放入優先級隊列中,且記錄爲已被訪問過
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(RainNode(i, j, heightMap[i][j]));
visit[i][j] = true;
}
}
}
// 一個點的x和y座標的四鄰域,按照上下左右的順序排列
vector<int> x = { 0,0,-1,1 }, y = { -1,1,0,0 };
while (!q.empty())
{
auto f = q.top(); //取出隊列q中最小的節點
// 當前格子的水平面高於海平面,海平面上升
// 否則,計算海水流進低於海平面的格子
if (h < f.h)
h++;
else
{
q.pop(); // 刪除隊列中最小的節點
// 當前格子的四個鄰域的格子,當座標不超出水池矩陣範圍且沒有被訪問過時,
for (int k = 0; k < 4; k++)
{
int i = f.i + x[k], j = f.j + y[k];
if (i >= 0 && i < m && j >= 0 && j < n && visit[i][j] == false)
{
int hh = heightMap[i][j];
if (hh < h)
area += h - hh;
q.push(RainNode(i, j, hh));
visit[i][j] = true;
}
}
}
}
return area;
}