3D接雨水——考察知識點

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;
    }


 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章