DFS與BFS LeetCode 刷題小結(一)

本節(jié)我們將匯總一些 LeetCode bfs與dfs相關的題。



關于深度優(yōu)先搜索(DFS)和廣度優(yōu)先搜索(BFS)苦酱,在往期博客中有所介紹,本節(jié)我們將介紹其他典題。

朋友圈

班上有 N 名學生库物。其中有些人是朋友,有些則不是贷帮。他們的友誼具有是傳遞性戚揭。如果已知 A 是 B 的朋友,B 是 C 的朋友撵枢,那么我們可以認為 A 也是 C 的朋友民晒。所謂的朋友圈,是指所有朋友的集合锄禽。

給定一個 N * N 的矩陣 M潜必,表示班級中學生之間的朋友關系。如果M[i][j] = 1沟绪,表示已知第 i 個和 j 個學生互為朋友關系刮便,否則為不知道。你必須輸出所有學生中的已知的朋友圈總數(shù)绽慈。

來源:https://leetcode-cn.com/problems/friend-circles

image.png

給出的數(shù)據(jù)是一個圖的鄰接矩陣恨旱,求得是該圖無向圖連通塊的個數(shù),對于這類問題坝疼,bfs和dfs都可以解決搜贤。

DFS版

我們需要一個vist來保存節(jié)點狀態(tài):

vector<bool> vist(M.size(),false);

當我們訪問一個節(jié)點時,訪問與它相鄰的節(jié)點钝凶,再訪問這個節(jié)點的相鄰節(jié)點仪芒,直到訪問到“底”唁影,每訪問一個節(jié)點改變它的狀態(tài),當遍歷到?jīng)]有訪問的相鄰節(jié)點時掂名,回溯之前的節(jié)點繼續(xù)訪問据沈。
程序如下:

class Solution {
public:
    int findCircleNum(vector<vector<int>>& M) {
        int len =M.size();
        vector<bool> vist(len,false);
        int res =0;
        for(int i=0;i<len;i++){
            if(!vist[i]){
                dfs(M,vist,i);
                res++;
            }
        }
        return res;
    }
    void dfs(vector<vector<int>>& M,vector<bool>& vist,int i){
        for(int j=0;j<M.size();j++){
            if(M[i][j]==1&&!vist[j]){
                vist[j]=true;
                dfs(M,vist,j);
            }
        }
    }
};

BFS版

廣度優(yōu)先就是一層層地來,類似于樹的層次遍歷饺蔑,需要用到隊列保存每層節(jié)點锌介,如果對樹的層序遍歷很熟悉,那圖的廣度優(yōu)先搜索也就不難了猾警。
程序如下:

class Solution {
public:
    int findCircleNum(vector<vector<int>>& M) {
        int len = M.size();
        int res=0;
        vector<bool> vist(len,false);
        queue<int> q;
        for(int i=0;i<len;i++){
            if(!vist[i]){
                q.push(i);
                while(!q.empty()){
                    int cur = q.front();
                    q.pop();
                    vist[cur]=true;
                    for(int j=0;j<len;j++){
                        if(M[cur][j]==1&&!vist[j]){
                            q.push(j);
                        }
                    }
                }
                res++;
            }
        }
        return res;
    }
};

這個題還有一種做法是并查集孔祸,本節(jié)我們暫不講述,在之后的章節(jié)會匯總并查集有關的題发皿。

島嶼數(shù)量

給定一個由 '1'(陸地)和 '0'(水)組成的的二維網(wǎng)格崔慧,計算島嶼的數(shù)量。一個島被水包圍穴墅,并且它是通過水平方向或垂直方向上相鄰的陸地連接而成的惶室。你可以假設網(wǎng)格的四個邊均被水包圍。

來源:https://leetcode-cn.com/problems/number-of-islands

image.png

這個題的思路和上面題類似封救,需要注意的地方便是處理的對象略有不同拇涤,上題是鄰接矩陣,來看具體的細節(jié)吧誉结。

DFS版

如果一個區(qū)域塊是1鹅士,是一塊陸地,我們要找到與它相鄰的1惩坑,在不越界的情況下掉盅,該塊上下左右若為1,則遞歸該塊繼續(xù)判斷其上下左右塊以舒,如果遞歸結束了趾痘,意味著是一塊陸地,因為一塊陸地的任意兩個點明顯是可達的(通過上下左右移動)蔓钟,在遞歸時永票,每到為1的塊,該塊置零滥沫。
程序如下:

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int rows = grid.size();
        if(rows==0){
            return 0;
        }
        int lists = grid[0].size();

        int lands = 0;
        for(int i=0;i<rows;i++){
            for(int j=0;j<lists;j++){
                if(grid[i][j]=='1'){
                    lands++;
                    dfs(grid,i,j);
                }
            }
        }
        return lands;
    }
    void dfs(vector<vector<char>>& grid,int i,int j){
        int rows=grid.size();
        int lists=grid[0].size();

        grid[i][j]='0';
        if(i>=1 && grid[i-1][j]=='1'){
            dfs(grid,i-1,j);
        }
        if(i<rows-1 && grid[i+1][j]=='1'){
            dfs(grid,i+1,j);
        }
        if(j>=1 && grid[i][j-1]=='1'){
            dfs(grid,i,j-1);
        }
        if(j<lists-1&&grid[i][j+1]=='1'){
            dfs(grid,i,j+1);
        }
    }
};

BFS版

BFS版其實也大同小異侣集,當處于陸地塊時,該塊置零兰绣,用一個隊列保存其上下左右的陸地塊世分,對于隊列里面的塊,在不越界的情況下判斷其上下左右缀辩,為1的塊入隊列臭埋,同時賦0踪央。
程序如下:

class Solution {
public:
    int numIslands(vector<vector<char>>& grid) {
        int rows= grid.size();
        if(rows==0){
            return 0;
        }
        int lists=grid[0].size();

        int lands=0;
        for(int i=0;i<rows;i++){
            for(int j=0;j<lists;j++){
                if(grid[i][j]=='1'){
                    lands++;
                    grid[i][j]='0';
                    queue<pair<int,int>> point;
                    point.push({i,j});
                    while(!point.empty()){
                        auto cur = point.front();
                        point.pop();
                        int i_=cur.first;
                        int j_=cur.second;
                        if(i_>=1 && grid[i_-1][j_]=='1'){
                            point.push({i_-1,j_});
                            grid[i_-1][j_]='0';
                        }
                        if(i_<rows-1 && grid[i_+1][j_]=='1'){
                            point.push({i_+1,j_});
                            grid[i_+1][j_]='0';
                        }
                        if(j_>=1 && grid[i_][j_-1]=='1'){
                            point.push({i_,j_-1});
                            grid[i_][j_-1]='0';
                        }
                        if(j_<lists-1 && grid[i_][j_+1]=='1'){
                            point.push({i_,j_+1});
                            grid[i_][j_+1]='0';
                        }
                    }
                }
            }
        }
        return lands;
    }
};

最后來看一道bfs的題。

腐爛的橘子

在給定的網(wǎng)格中瓢阴,每個單元格可以有以下三個值之一:

值 0 代表空單元格畅蹂;
值 1 代表新鮮橘子;
值 2 代表腐爛的橘子荣恐。
每分鐘魁莉,任何與腐爛的橘子(在 4 個正方向上)相鄰的新鮮橘子都會腐爛。

返回直到單元格中沒有新鮮橘子為止所必須經(jīng)過的最小分鐘數(shù)募胃。如果不可能,返回 -1畦浓。

來源:https://leetcode-cn.com/problems/rotting-oranges

image.png

這個題很明顯使用廣度優(yōu)先搜索痹束,從爛橘子出發(fā),在不越界的情況下讶请,其上下左右的橘子都會爛掉祷嘶,計時,統(tǒng)計這個過程爛掉的橘子數(shù)夺溢,若等于原始好的橘子數(shù)论巍,返回時間,否則為-1风响。
程序如下:

class Solution {
public:
    int orangesRotting(vector<vector<int>>& grid) {
        int min=0,fresh=0;
        queue<pair<int,int>> q;
        for(int i=0;i<grid.size();i++){
            for(int j=0;j<grid[0].size();j++){
                if(grid[i][j]==1){
                    //新鮮橘子
                    fresh++;
                }else if(grid[i][j]==2){
                    //腐爛的橘子
                    q.push({i,j});
                }
            }
        }
        vector<pair<int,int>> dirs={{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        while(!q.empty()){
            int n=q.size();
            bool sign=false;
            while(n--){
                auto point=q.front();
                q.pop();
                for(auto cur : dirs){
                    int i=point.first+cur.first;
                    int j=point.second+cur.second;
                    if(i>=0&&i<grid.size()&&j>=0&&j<grid[0].size()&&grid[i][j]==1){
                        grid[i][j]=2;
                        q.push({i,j});
                        fresh--;
                        sign=true;
                    }
                }
            }
            if(sign){
                min++;
            }
        }
        return fresh?-1:min;
    }
};

本節(jié)內容暫告一段落嘉汰,之后將繼續(xù)更新。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末状勤,一起剝皮案震驚了整個濱河市鞋怀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌持搜,老刑警劉巖密似,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異葫盼,居然都是意外死亡残腌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門贫导,熙熙樓的掌柜王于貴愁眉苦臉地迎上來抛猫,“玉大人,你說我怎么就攤上這事脱盲∫乇酰” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵钱反,是天一觀的道長掖看。 經(jīng)常有香客問我匣距,道長,這世上最難降的妖魔是什么哎壳? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任毅待,我火速辦了婚禮,結果婚禮上归榕,老公的妹妹穿的比我還像新娘尸红。我一直安慰自己,他們只是感情好刹泄,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布外里。 她就那樣靜靜地躺著,像睡著了一般特石。 火紅的嫁衣襯著肌膚如雪盅蝗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天姆蘸,我揣著相機與錄音墩莫,去河邊找鬼。 笑死逞敷,一個胖子當著我的面吹牛狂秦,可吹牛的內容都是我干的。 我是一名探鬼主播推捐,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼裂问,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了牛柒?” 一聲冷哼從身側響起愕秫,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎焰络,沒想到半個月后戴甩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡闪彼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年甜孤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片畏腕。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡缴川,死狀恐怖,靈堂內的尸體忽然破棺而出描馅,到底是詐尸還是另有隱情把夸,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布铭污,位于F島的核電站恋日,受9級特大地震影響膀篮,放射性物質發(fā)生泄漏。R本人自食惡果不足惜岂膳,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一誓竿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧谈截,春花似錦筷屡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至喻鳄,卻和暖如春规哲,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背诽表。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留隅肥,地道東北人竿奏。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像腥放,于是被迫代替她去往敵國和親泛啸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內容