日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

蓝桥杯算法竞赛系列第八章——提高篇之广度优先搜索(BFS)

發(fā)布時(shí)間:2023/12/20 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 蓝桥杯算法竞赛系列第八章——提高篇之广度优先搜索(BFS) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

??

歡迎回到:遇見藍(lán)橋遇見你,不負(fù)代碼不負(fù)卿!

目錄

一、廣度優(yōu)先搜索算法(BFS)?

典例一:二叉搜索樹的范圍和

方法一:DFS解法

方法二:BFS解法

典例二:二叉樹的層序遍歷

典例三:二叉樹的層序遍歷 II

典例四:島嶼數(shù)量

方法一:DFS解法?

方法二:BFS解法

五、易錯(cuò)誤區(qū)

六、藍(lán)橋結(jié)語(yǔ):遇見藍(lán)橋遇見你,不負(fù)代碼不負(fù)卿!

【前言】

搜索算法在藍(lán)橋中考的還是很頻繁的,之前發(fā)表了二叉樹數(shù)據(jù)結(jié)構(gòu)以及深度優(yōu)先搜索章節(jié),前面還是比較簡(jiǎn)單的,這里的廣度優(yōu)先搜索可能稍微復(fù)雜那么一丟丟,因?yàn)橐玫疥?duì)列,不過我們可以使用STL容器也是很方便就解決了。?

【聲明】:由于前半部分是基礎(chǔ)知識(shí)點(diǎn)定義部分,所以前面一小半部分的贅述筆者是參考力扣官方給出的定義以及《算法筆記》一書。

一、廣度優(yōu)先搜索算法(BFS)?

對(duì)于廣度優(yōu)先搜索的定義及特點(diǎn),力扣官方是這樣給出的:?

廣度優(yōu)先搜索算法(Breadth-First Search,縮寫為 BFS),又稱為寬度優(yōu)先搜索,是一種圖形搜索算法。簡(jiǎn)單的說(shuō),BFS是從根節(jié)點(diǎn)開始,沿著樹的寬度遍歷樹的節(jié)點(diǎn)。廣度優(yōu)先搜索也廣泛應(yīng)用于圖論問題中。?

齊頭并進(jìn)的廣度優(yōu)先遍歷

??

?

說(shuō)明遍歷到一個(gè)結(jié)點(diǎn)時(shí),如果這個(gè)結(jié)點(diǎn)有左(右)孩子結(jié)點(diǎn),依次將它們加入隊(duì)列。?

可能上面講的不夠細(xì)節(jié),下面詳細(xì)介紹何為”廣搜”:

首先呢,鐵汁們先將之前的DFS章節(jié)前面的迷宮問題再回顧一下,知道何為“死胡同”以及“岔道口”

https://blog.csdn.net/weixin_57544072/article/details/121262172https://blog.csdn.net/weixin_57544072/article/details/121262172https://blog.csdn.net/weixin_57544072/article/details/121262172

前面介紹了深度優(yōu)先搜索,可知DFS是以深度作為第一關(guān)鍵詞的,即當(dāng)岔道口時(shí)總是先選擇其中的一條岔道前進(jìn),而不管其他岔路,直到碰到死胡同時(shí)才返回岔道口并選擇其他岔路。接下來(lái)將介紹的廣度優(yōu)先搜索(Breadth First Search, BFS)則是以廣度為第一關(guān)鍵詞,當(dāng)碰到岔道口時(shí),總是先依次訪問從該岔道口能直接到達(dá)的所有節(jié)點(diǎn),然后再按這些節(jié)點(diǎn)被訪問的順序去依次訪問它們能直接到達(dá)的所有節(jié)點(diǎn),以此類推,直到所有節(jié)點(diǎn)都被訪問為止。

這就跟在平靜的水面中投入一顆小石子一樣,水花總是以石子落水處為中心,并以同心圓的方式向外擴(kuò)散至整個(gè)水面,從這點(diǎn)來(lái)看和DFS那種沿著一條線前進(jìn)的思路是完全不同的。

概念部分就講這么多咯,我呢一直是以講題目練習(xí)為主,OK,廢話不多說(shuō),咱們走起來(lái)!

??

典例一:二叉搜索樹的范圍和

原題鏈接:https://leetcode-cn.com/problems/range-sum-of-bst/https://leetcode-cn.com/problems/range-sum-of-bst/https://leetcode-cn.com/problems/range-sum-of-bst/

注意:二叉搜索樹的特點(diǎn)就是左子樹都比根要小,右子樹都比根要大!?

題目描述:

示例1:

輸入:root = [10,5,15,3,7,null,18], low = 7, high = 15 輸出:32

示例2:

輸入:root = [10,5,15,3,7,13,18,1,null,6], low = 6, high = 10 輸出:23

方法一:DFS解法

思路:

本題很簡(jiǎn)單,鐵汁們看代碼里面的注釋就能理解啦。

代碼執(zhí)行:

/*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/int rangeSumBST(struct TreeNode* root, int low, int high){// //方法一:遞歸法// //找邊界// if(root == NULL){// return 0;// }// //左子樹// int leftSum = rangeSumBST(root->left, low, high);// //右子樹// int rightSum = rangeSumBST(root->right, low, high);// int result = leftSum + rightSum;// //判斷根節(jié)點(diǎn)// if(root->val >= low && root->val <= high){// result += root->val;// }// return result;//方法二:DFS//判斷特殊情況if(root == NULL){return 0;}//如果根節(jié)點(diǎn)的值大于high,那么右子樹不滿足,此時(shí)只需要判斷左子樹if(root->val > high){return rangeSumBST(root->left, low, high);}//如果根節(jié)點(diǎn)的值小于low,那么左子樹一定不滿足,此時(shí)只需要判斷右子樹if(root->val < low){return rangeSumBST(root->right, low, high);}//否則如果根節(jié)點(diǎn)的值在low和high之間,那么三者都需要判斷return root->val + rangeSumBST(root->left, low, high) + rangeSumBST(root->right, low, high); }

方法二:BFS解法

思路:

使用廣度優(yōu)先搜索的方法,用一個(gè)隊(duì)列?q?存儲(chǔ)需要計(jì)算的節(jié)點(diǎn)每次取出隊(duì)首節(jié)點(diǎn)時(shí),若節(jié)點(diǎn)為空則跳過該節(jié)點(diǎn),否則按方法一中給出的大小關(guān)系來(lái)決定加入隊(duì)列的子節(jié)點(diǎn)。

代碼執(zhí)行:

/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/ class Solution { public:int rangeSumBST(TreeNode* root, int low, int high) {queue<TreeNode*>q;//定義一個(gè)隊(duì)列//首先將根節(jié)點(diǎn)入隊(duì)if(root)q.push(root);int res = 0;while(!q.empty())//隊(duì)列非空時(shí)循環(huán)繼續(xù){int n = q.size();//隊(duì)列的長(zhǎng)度f(wàn)or(int i = 0; i < n; i++){TreeNode* t = q.front();//訪問隊(duì)首元素q.pop();//隊(duì)首元素出隊(duì)//注意輸入格式中有空節(jié)點(diǎn),所以要加一個(gè)判斷//當(dāng)訪問到的節(jié)點(diǎn)是空節(jié)點(diǎn)時(shí),跳過該節(jié)點(diǎn)if(t == nullptr){continue;}//注意哦,由于是二叉搜索樹,有它自己的特性//節(jié)點(diǎn)的值大于high時(shí),只需要左子樹入隊(duì)if(t->val > high)q.push(t->left);//節(jié)點(diǎn)的值小于low時(shí),只需要右子樹入隊(duì)if(t->val < low)q.push(t->right);//節(jié)點(diǎn)的值在low和high之間時(shí),需要加上該節(jié)點(diǎn)值以及左右子樹入隊(duì)if(t->val >= low && t->val <= high){res += t->val;q.push(t->left);q.push(t->right);}}}return res;} };

??

典例二:二叉樹的層序遍歷

原題鏈接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal/https://leetcode-cn.com/problems/binary-tree-level-order-traversal/https://leetcode-cn.com/problems/binary-tree-level-order-traversal/

題目描述:

示例:

思路:

代碼中注釋給得很詳細(xì)咯,快去康康叭。?

代碼執(zhí)行:

class Solution { public:/*** * @param root TreeNode* * @return int整型vector<vector<>>*/vector<vector<int> > levelOrder(TreeNode* root) {// write code herequeue<TreeNode*>q;//定義一個(gè)隊(duì)列if(root)q.push(root);vector<vector<int> >ans;//定義一個(gè)二維數(shù)組用于存放遍歷結(jié)果while(!q.empty()){//隊(duì)列為空時(shí)停下來(lái)int n = q.size();//注意哦,n不能放在循環(huán)外邊,隊(duì)列中的元素是在變化的vector<int>tmp;//定義一維數(shù)組用于存放每一層的節(jié)點(diǎn)(注意一維數(shù)組定義的位置)for(int i = 0;i < n;i++){TreeNode* t = q.front();//訪問隊(duì)首元素q.pop();//隊(duì)首元素出隊(duì)tmp.push_back(t->val);//將隊(duì)首元素的值存放到該層的一維數(shù)組中if(t->left)//左子節(jié)點(diǎn)入隊(duì)q.push(t->left);if(t->right)//右子節(jié)點(diǎn)入隊(duì)q.push(t->right);}ans.push_back(tmp);//將第一層的一維數(shù)組存放二維數(shù)組中}return ans;} };

??

典例三:二叉樹的層序遍歷 II

原題鏈接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/https://leetcode-cn.com/problems/binary-tree-level-order-traversal-ii/

題目描述:

示例:

思路:

哈哈,本題主要是讓大家熟練掌握二叉樹的層序遍歷才添加進(jìn)來(lái)的,本題呢,直接將最后存放到二維數(shù)組中的數(shù)據(jù)反轉(zhuǎn)(#include<algorithm>頭文件下)即可。?

代碼執(zhí)行:

/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/ class Solution { public:vector<vector<int>> levelOrderBottom(TreeNode* root) {//定義一個(gè)隊(duì)列queue<TreeNode*>q;//定義一個(gè)二維數(shù)組用于返回結(jié)果vector<vector<int> >ans;//先將根節(jié)點(diǎn)入隊(duì)if(root)q.push(root);while(!q.empty()){//定義一個(gè)一維數(shù)組用于存放每一層節(jié)點(diǎn)的值vector<int>temp;int n = q.size();//隊(duì)列的長(zhǎng)度f(wàn)or(int i = 0; i < n; i++){//訪問隊(duì)首元素TreeNode* t = q.front();//隊(duì)首元素出隊(duì)q.pop();//將隊(duì)首元素的值存放到一維數(shù)組中temp.push_back(t->val);//訪問左子樹if(t->left)q.push(t->left);//訪問右子樹if(t->right)q.push(t->right);}ans.push_back(temp);}reverse(ans.begin(), ans.end());//反轉(zhuǎn)二維數(shù)組中的結(jié)果return ans;} };

??

典例四:島嶼數(shù)量

原題鏈接:https://leetcode-cn.com/problems/number-of-islands/https://leetcode-cn.com/problems/number-of-islands/https://leetcode-cn.com/problems/number-of-islands/

題目描述:

示例1:

輸入:grid = [["1","1","1","1","0"],["1","1","0","1","0"],["1","1","0","0","0"],["0","0","0","0","0"] ] 輸出:1

示例2:

輸入:grid = [["1","1","0","0","0"],["1","1","0","0","0"],["0","0","1","0","0"],["0","0","0","1","1"] ] 輸出:3

方法一:DFS解法?

思路:

為了求出島嶼的數(shù)量,我們可以掃描整個(gè)二維網(wǎng)格。如果一個(gè)位置為 1,則以其為起始節(jié)點(diǎn)開始進(jìn)行深度優(yōu)先搜索。在深度優(yōu)先搜索的過程中,每個(gè)搜索到的 1 都會(huì)被重新標(biāo)記為 0(也就是下面代碼中所說(shuō)的“同化”)

代碼執(zhí)行:

int numIslands(char** grid, int gridSize, int* gridColSize){//找遞歸邊界if(grid == NULL || gridSize == 0){return 0;}int row = gridSize;//行數(shù)int col = *gridColSize;//列數(shù)int count = 0;//用于計(jì)數(shù)int i = 0;int j = 0;//遍歷這個(gè)二維網(wǎng)格for(i = 0; i < row; i++){for(j = 0; j < col; j++){if(grid[i][j] == '1'){count++;//將‘1’周圍的‘1’全部同化成0dfs(grid, i, j, row, col);}}}return count; }void dfs(char** grid, int x, int y, int row, int col) {//判斷特殊情況if(x < 0 || x >= row || y < 0 || y >= col || grid[x][y] == '0')//注意哦,下標(biāo)等于行數(shù)列數(shù)時(shí)也是不可以的喲{return;}grid[x][y] = '0';//將‘1’同化成0dfs(grid, x - 1, y, row, col);dfs(grid, x + 1, y, row, col);dfs(grid, x, y - 1, row, col);dfs(grid, x, y + 1, row, col); }

方法二:BFS解法

思路:

同樣地,我們也可以使用廣度優(yōu)先搜索代替深度優(yōu)先搜索。

為了求出島嶼的數(shù)量,我們可以掃描整個(gè)二維網(wǎng)格。如果一個(gè)位置為 1,則將其加入隊(duì)列(注意哦,是將其對(duì)應(yīng)的下標(biāo)存放到隊(duì)列中的)開始進(jìn)行廣度優(yōu)先搜索。在廣度優(yōu)先搜索的過程中,每個(gè)搜索到的 1 都會(huì)被重新標(biāo)記為 0。直到隊(duì)列為空,搜索結(jié)束。

代碼執(zhí)行:

//由于需要用到queue和pair容器,所以選擇C++編寫代碼 class Solution { public:int numIslands(vector<vector<char>>& grid) {int nr = grid.size();//行數(shù)if (!nr) return 0;//判斷邊界情況int nc = grid[0].size();//列數(shù)int num_islands = 0;//用于計(jì)數(shù)//遍歷二維網(wǎng)格for (int r = 0; r < nr; ++r) {for (int c = 0; c < nc; ++c) {//滿足條件時(shí)進(jìn)來(lái),否則進(jìn)入下一次循環(huán)if (grid[r][c] == '1') {++num_islands;grid[r][c] = '0';//定義一個(gè)隊(duì)列,用于存放下標(biāo)信息//注意對(duì)pair的理解,可以看作是內(nèi)部有兩個(gè)元素的結(jié)構(gòu)體queue<pair<int, int>> neighbors;neighbors.push({r, c});//將'1'的下標(biāo)信息入隊(duì)while (!neighbors.empty()) {pair<int,int> rc = neighbors.front();//訪問隊(duì)首元素neighbors.pop();//隊(duì)首元素出隊(duì)int row = rc.first;//隊(duì)首元素所對(duì)應(yīng)的行號(hào)int col = rc.second;//隊(duì)首元素所對(duì)應(yīng)的列號(hào)//將它上下左右的‘1’都同化成‘0’//上//row - 1 >= 0 判斷位置是否合法if (row - 1 >= 0 && grid[row-1][col] == '1') {neighbors.push({row-1, col});grid[row-1][col] = '0';}//下//row + 1 < nr 判斷位置是否合法if (row + 1 < nr && grid[row+1][col] == '1') {neighbors.push({row+1, col});grid[row+1][col] = '0';}//左//col - 1 >= 0 判斷位置是否合法if (col - 1 >= 0 && grid[row][col-1] == '1') {neighbors.push({row, col-1});grid[row][col-1] = '0';}//右//col + 1 < nc 判斷位置是否合法if (col + 1 < nc && grid[row][col+1] == '1') {neighbors.push({row, col+1});grid[row][col+1] = '0';}}}}}return num_islands;} };

五、易錯(cuò)誤區(qū)

最后需要指出的是,當(dāng)使用STL的queue時(shí),元素入隊(duì)的push操作只是制造了該元素的一個(gè)副本入隊(duì),因此在入隊(duì)后對(duì)原元素的修改是不會(huì)影響隊(duì)列中的副本,同樣的,對(duì)隊(duì)列中副本的修改也不會(huì)改變?cè)?#xff0c;需要注意由此可能引入的bug!?

例如下面這個(gè)例子:

#include<cstdio> #include<queue>using namespace std;struct node {int data; }a[10];int main() {queue<int> q;for (int i = 1; i <= 3; i++){a[i].data = i;//a[1] = 1, a[2] = 2, a[3] = 3q.push(a[i]);}//嘗試直接把隊(duì)首元素(即a[1])的數(shù)據(jù)域改為100q.front().data = 100;//事實(shí)上對(duì)隊(duì)列元素的修改無(wú)法改變?cè)豴rintf("%d %d %d\n", a[1].data, a[2].data, a[3].data);//輸出1 2 3 注意哦,并不是100 2 3//嘗試直接修改a[1]的數(shù)據(jù)域?yàn)?00(即a[1],上面已經(jīng)修改為100)a[1].data = 200;//事實(shí)上對(duì)原元素的修改也無(wú)法改變隊(duì)列中的元素printf("%d\n", q.front().data);//輸出100 注意哦,并不是200return 0; }

發(fā)現(xiàn)上面出現(xiàn)的問題了嗎,這就是說(shuō),當(dāng)需要對(duì)隊(duì)列中的元素進(jìn)行修改而不僅僅是訪問時(shí),隊(duì)列中存放的元素最好不要是元素本身,而是它們對(duì)應(yīng)的編號(hào)(如果是數(shù)組的話則是下標(biāo))。

例如把上面的程序改成下面這樣:

#include<stdio.h> #include<queue> using namespace std;struct node {int data; }a[10];int main() {queue<int> q;//q存放數(shù)組中元素的下標(biāo)for (int i = 1; i <= 3; i++){a[i].data = i;//a[1] = 1, a[2] = 2, a[3] = 3q.push(i);//這里是將數(shù)組下標(biāo)i入隊(duì),而不是節(jié)點(diǎn)a[i]本身}a[q.front()].data = 100;//q.front()為下標(biāo),通過a[q.front()]即可修改原元素printf("%d\n", a[1].data);//輸出100return 0; }

?

六、藍(lán)橋結(jié)語(yǔ):遇見藍(lán)橋遇見你,不負(fù)代碼不負(fù)卿!

搜索的基礎(chǔ)部分到這里就結(jié)束咯,不過嘞,不會(huì)這么簡(jiǎn)單就結(jié)束掉的,后面的話筆者還會(huì)出一個(gè)藍(lán)橋杯沖刺專欄,還有大量的練習(xí)以及相當(dāng)一部分的真題!OK,今天就到這里咯,下一章節(jié)講的是動(dòng)態(tài)規(guī)劃(DP)哈。

如果大家有所收獲的話,麻煩給俺個(gè)三連唄,萬(wàn)分感謝,抱拳了哈。

總結(jié)

以上是生活随笔為你收集整理的蓝桥杯算法竞赛系列第八章——提高篇之广度优先搜索(BFS)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。