算法學(xué)習(xí)之寬度優(yōu)先搜索

寬度優(yōu)先搜索又稱廣度優(yōu)先搜索揽涮,簡(jiǎn)稱bfs猴娩。
搜索的方式是:從一個(gè)點(diǎn)開(kāi)始阴幌,逐層的遍歷訪問(wèn)周?chē)狞c(diǎn)勺阐。比如有一個(gè)5*5的矩陣,每次可以訪問(wèn)某個(gè)點(diǎn)周?chē)邪藗€(gè)點(diǎn)矛双,則如果從中心點(diǎn)開(kāi)始寬度搜索渊抽,只需兩層即可遍歷完整個(gè)矩陣。
寬度搜索可用于對(duì)樹(shù)议忽、圖懒闷、矩陣等進(jìn)行搜索,適合用于求最短路徑等問(wèn)題栈幸。
算法關(guān)鍵詞:隊(duì)列愤估,利用隊(duì)列先進(jìn)先出的特點(diǎn)。隊(duì)列中存儲(chǔ)待遍歷的點(diǎn)速址,如果隊(duì)列不空玩焰,就從隊(duì)列中取出第一個(gè)元素,將此元素標(biāo)記為已訪問(wèn)芍锚,再把與這個(gè)元素相鄰的未被標(biāo)記的元素添加到隊(duì)列末尾昔园,循環(huán)直到隊(duì)列變?yōu)榭铡哪硞€(gè)點(diǎn)開(kāi)始搜索并炮,只需要先把這個(gè)點(diǎn)添加到隊(duì)列中默刚,然后開(kāi)始遍歷的操作。
個(gè)人覺(jué)得寬度優(yōu)先搜索還是很容易學(xué)的逃魄,因?yàn)樗乃枷肴菀桌斫饣缥鳎覍?xiě)的套路很固定。
實(shí)際應(yīng)用:爬蟲(chóng)伍俘。爬蟲(chóng)一般是首先將幾個(gè)母站添加到爬蟲(chóng)隊(duì)列邪锌;然后從隊(duì)列中取出要爬的網(wǎng)站,分析網(wǎng)頁(yè)中包含的鏈接养篓,將鏈接添加到爬蟲(chóng)隊(duì)列秃流,再爬取網(wǎng)站內(nèi)容;不斷往復(fù)這個(gè)操作柳弄,這和寬度搜索的執(zhí)行方式幾乎是一樣的舶胀。
下面做幾道題來(lái)練習(xí):
1、給一個(gè)01矩陣碧注,求不同的島嶼的個(gè)數(shù)嚣伐。0代表海,1代表島萍丐,如果兩個(gè)1相鄰轩端,那么這兩個(gè)1屬于同一個(gè)島。我們只考慮上下左右為相鄰逝变。
樣例
[
[1, 1, 0, 0, 0],
[0, 1, 0, 0, 1],
[0, 0, 0, 1, 1],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1]
]
上圖矩陣有3個(gè)島基茵。
思路:遍歷圖奋构,只要找到一個(gè)島,就對(duì)這個(gè)島進(jìn)行寬搜拱层,把和它相鄰的所有島都找出來(lái)并且標(biāo)記,這樣一個(gè)大島就找到了根灯。當(dāng)整個(gè)圖被遍歷后径缅,也就找到了所有大島的個(gè)數(shù)。

<?php
class Coor {
    public $x;
    public $y;
    
    function __construct($x, $y) {
        $this->x = $x;
        $this->y = $y;
    }
}
function numIslands($grid) {
    if (!$grid || sizeof($grid) == 0 || sizeof($grid[0]) == 0) {
        return 0;
    }
    
    $n = sizeof($grid);
    $m = sizeof($grid[0]);
    $num = 0;//島嶼個(gè)數(shù)
    
    for ($i = 0; $i < $n; $i++) {
        for ($j = 0; $j < $m; $j++) {
            if ($grid[$i][$j]) {
                //搜索和這個(gè)島相鄰的所有島
                bfs($grid, $i, $j);
                $num++;
            }
        }
    }
    
    return $num;
}
function bfs(&$grid, $x, $y) {
    $directX = [-1, 0, 1, 0];
    $directY = [0, 1, 0, -1];
    
    $queue = [];
    array_push($queue, new Coor($x, $y));
    $gird[$x][$y] = false;//將已訪問(wèn)的標(biāo)記
    
    while ($queue) {
        $tmpCor = array_shift($queue);
        for ($i = 0; $i < 4; $i++) {
            $tx = $tmpCor->x + $directX[$i];
            $ty = $tmpCor->y + $directY[$i];
            //在邊界內(nèi)并且是島嶼
            if (inBound($grid, $tx, $ty) && $grid[$tx][$ty]) {
                array_push($queue, new Coor($tx, $ty));
                $grid[$tx][$ty] = false;
            }
        }
    }
}
function inBound($grid, $x, $y) {
    $n = sizeof($grid);
    $m = sizeof($grid[0]);
    
    return $x >= 0 && $x < $n && $y >= 0 && $y < $m;
}

2烙肺、給定一個(gè)矩陣纳猪,2代表墻,1代表僵尸桃笙,0代表人氏堤。僵尸每天可以將上下左右與之相鄰的人咬成僵尸,但是僵尸不能穿墻搏明。求將所有的人變?yōu)榻┦枰獛滋炖鲡绻荒苋孔優(yōu)榻┦祷?1.
0 1 2 0 0
1 0 0 2 1
0 1 0 0 0
如上圖return 2。
思路:首先我們應(yīng)該統(tǒng)計(jì)出當(dāng)前的人數(shù)熏瞄,然后將圖中所有僵尸坐標(biāo)加入隊(duì)列,對(duì)隊(duì)列中的點(diǎn)進(jìn)行搜索谬以,每遍歷一層增加一天(很重要)强饮,搜索過(guò)程中遇到人就將人數(shù)-1。最后看人數(shù)如果歸零为黎,證明全部變?yōu)榻┦史幔祷靥鞌?shù),否則返回-1.

class Coor {
    public $x;
    public $y;
    
    function __construct($x, $y) {
        $this->x = $x;
        $this->y = $y;
    }
}
function zombie($grid) {
    if (!$grid || sizeof($grid) == 0 || sizeof($grid[0]) == 0) {
        return 0;
    }
    
    $n = sizeof($grid);
    $m = sizeof($grid[0]);
    $people = 0;//人數(shù)
    $day = 0;//天數(shù)
    $queue = [];
    
    //初始化已知條件
    for ($i = 0; $i < $n; $i++) {
        for ($j = 0; $j < $m; $j++) {
            if ($grid[$i][$j] == 0) {
                $people++;
            }
            if ($grid[$i][$j] == 1) {
                array_push($queue, new Coor($i, $j));
            }
        }
    }
    
    //僵尸感染過(guò)程C<袅!
    $directX = [-1, 0, 1, 0];
    $directY = [0, 1, 0, -1];
    while ($queue) {
        $day++;
        $cnt = sizeof($queue);
        for ($i = 0; $i < $cnt; $i++) {
            $cor = array_shift($queue);
            for ($j = 0; $j < 4; $j++) {
                $tx = $cor->x + $directX[$j];
                $ty = $cor->y + $directY[$j];
                if (inBound($grid, $tx, $ty) && $grid[$tx][$ty] == 0) {
                    $people--;
                    $grid[$tx][$ty] = 1;
                    array_push($queue, new Coor($tx, $ty));
                }
            }
            
        }
        if ($people == 0) {
            return $day;
        }
    }
    
    return -1;
}
function inBound($grid, $x, $y) {
    $n = sizeof($grid);
    $m = sizeof($grid[0]);
    
    return $x >= 0 && $x < $n && $y >= 0 && $y < $m;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末炕檩,一起剝皮案震驚了整個(gè)濱河市斗蒋,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌笛质,老刑警劉巖泉沾,帶你破解...
    沈念sama閱讀 216,919評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異妇押,居然都是意外死亡跷究,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)敲霍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)俊马,“玉大人丁存,你說(shuō)我怎么就攤上這事〔裎遥” “怎么了解寝?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,316評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)屯换。 經(jīng)常有香客問(wèn)我编丘,道長(zhǎng),這世上最難降的妖魔是什么彤悔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,294評(píng)論 1 292
  • 正文 為了忘掉前任嘉抓,我火速辦了婚禮,結(jié)果婚禮上晕窑,老公的妹妹穿的比我還像新娘抑片。我一直安慰自己,他們只是感情好杨赤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,318評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布敞斋。 她就那樣靜靜地躺著,像睡著了一般疾牲。 火紅的嫁衣襯著肌膚如雪植捎。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,245評(píng)論 1 299
  • 那天阳柔,我揣著相機(jī)與錄音焰枢,去河邊找鬼。 笑死舌剂,一個(gè)胖子當(dāng)著我的面吹牛济锄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播霍转,決...
    沈念sama閱讀 40,120評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼荐绝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了避消?” 一聲冷哼從身側(cè)響起低滩,我...
    開(kāi)封第一講書(shū)人閱讀 38,964評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎沾谓,沒(méi)想到半個(gè)月后委造,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,376評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡均驶,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,592評(píng)論 2 333
  • 正文 我和宋清朗相戀三年昏兆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片妇穴。...
    茶點(diǎn)故事閱讀 39,764評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爬虱,死狀恐怖隶债,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情跑筝,我是刑警寧澤死讹,帶...
    沈念sama閱讀 35,460評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站曲梗,受9級(jí)特大地震影響赞警,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虏两,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,070評(píng)論 3 327
  • 文/蒙蒙 一愧旦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧定罢,春花似錦笤虫、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,697評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至惠况,卻和暖如春遭庶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背稠屠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,846評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工罚拟, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人完箩。 一個(gè)月前我還...
    沈念sama閱讀 47,819評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像拉队,于是被迫代替她去往敵國(guó)和親弊知。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,665評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容