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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

??

歡迎回到:遇見藍橋遇見你,不負代碼不負卿!

目錄

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

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

方法一:DFS解法

方法二:BFS解法

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

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

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

方法一:DFS解法?

方法二:BFS解法

五、易錯誤區(qū)

六、藍橋結語:遇見藍橋遇見你,不負代碼不負卿!

【前言】

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

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

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

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

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

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

??

?

說明遍歷到一個結點時,如果這個結點有左(右)孩子結點,依次將它們加入隊列。?

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

首先呢,鐵汁們先將之前的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是以深度作為第一關鍵詞的,即當岔道口時總是先選擇其中的一條岔道前進,而不管其他岔路,直到碰到死胡同時才返回岔道口并選擇其他岔路。接下來將介紹的廣度優(yōu)先搜索(Breadth First Search, BFS)則是以廣度為第一關鍵詞,當碰到岔道口時,總是先依次訪問從該岔道口能直接到達的所有節(jié)點,然后再按這些節(jié)點被訪問的順序去依次訪問它們能直接到達的所有節(jié)點,以此類推,直到所有節(jié)點都被訪問為止。

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

概念部分就講這么多咯,我呢一直是以講題目練習為主,OK,廢話不多說,咱們走起來!

??

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

原題鏈接: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/

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

題目描述:

示例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解法

思路:

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

代碼執(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é)點// if(root->val >= low && root->val <= high){// result += root->val;// }// return result;//方法二:DFS//判斷特殊情況if(root == NULL){return 0;}//如果根節(jié)點的值大于high,那么右子樹不滿足,此時只需要判斷左子樹if(root->val > high){return rangeSumBST(root->left, low, high);}//如果根節(jié)點的值小于low,那么左子樹一定不滿足,此時只需要判斷右子樹if(root->val < low){return rangeSumBST(root->right, low, high);}//否則如果根節(jié)點的值在low和high之間,那么三者都需要判斷return root->val + rangeSumBST(root->left, low, high) + rangeSumBST(root->right, low, high); }

方法二:BFS解法

思路:

使用廣度優(yōu)先搜索的方法,用一個隊列?q?存儲需要計算的節(jié)點每次取出隊首節(jié)點時,若節(jié)點為空則跳過該節(jié)點,否則按方法一中給出的大小關系來決定加入隊列的子節(jié)點。

代碼執(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;//定義一個隊列//首先將根節(jié)點入隊if(root)q.push(root);int res = 0;while(!q.empty())//隊列非空時循環(huán)繼續(xù){int n = q.size();//隊列的長度for(int i = 0; i < n; i++){TreeNode* t = q.front();//訪問隊首元素q.pop();//隊首元素出隊//注意輸入格式中有空節(jié)點,所以要加一個判斷//當訪問到的節(jié)點是空節(jié)點時,跳過該節(jié)點if(t == nullptr){continue;}//注意哦,由于是二叉搜索樹,有它自己的特性//節(jié)點的值大于high時,只需要左子樹入隊if(t->val > high)q.push(t->left);//節(jié)點的值小于low時,只需要右子樹入隊if(t->val < low)q.push(t->right);//節(jié)點的值在low和high之間時,需要加上該節(jié)點值以及左右子樹入隊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/

題目描述:

示例:

思路:

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

代碼執(zhí)行:

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

題目描述:

示例:

思路:

哈哈,本題主要是讓大家熟練掌握二叉樹的層序遍歷才添加進來的,本題呢,直接將最后存放到二維數(shù)組中的數(shù)據(jù)反轉(#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) {//定義一個隊列queue<TreeNode*>q;//定義一個二維數(shù)組用于返回結果vector<vector<int> >ans;//先將根節(jié)點入隊if(root)q.push(root);while(!q.empty()){//定義一個一維數(shù)組用于存放每一層節(jié)點的值vector<int>temp;int n = q.size();//隊列的長度for(int i = 0; i < n; i++){//訪問隊首元素TreeNode* t = q.front();//隊首元素出隊q.pop();//將隊首元素的值存放到一維數(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());//反轉二維數(shù)組中的結果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ù)量,我們可以掃描整個二維網(wǎng)格。如果一個位置為 1,則以其為起始節(jié)點開始進行深度優(yōu)先搜索。在深度優(yōu)先搜索的過程中,每個搜索到的 1 都會被重新標記為 0(也就是下面代碼中所說的“同化”)

代碼執(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;//用于計數(shù)int i = 0;int j = 0;//遍歷這個二維網(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')//注意哦,下標等于行數(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ù)量,我們可以掃描整個二維網(wǎng)格。如果一個位置為 1,則將其加入隊列(注意哦,是將其對應的下標存放到隊列中的)開始進行廣度優(yōu)先搜索。在廣度優(yōu)先搜索的過程中,每個搜索到的 1 都會被重新標記為 0。直到隊列為空,搜索結束。

代碼執(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;//用于計數(shù)//遍歷二維網(wǎng)格for (int r = 0; r < nr; ++r) {for (int c = 0; c < nc; ++c) {//滿足條件時進來,否則進入下一次循環(huán)if (grid[r][c] == '1') {++num_islands;grid[r][c] = '0';//定義一個隊列,用于存放下標信息//注意對pair的理解,可以看作是內部有兩個元素的結構體queue<pair<int, int>> neighbors;neighbors.push({r, c});//將'1'的下標信息入隊while (!neighbors.empty()) {pair<int,int> rc = neighbors.front();//訪問隊首元素neighbors.pop();//隊首元素出隊int row = rc.first;//隊首元素所對應的行號int col = rc.second;//隊首元素所對應的列號//將它上下左右的‘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;} };

五、易錯誤區(qū)

最后需要指出的是,當使用STL的queue時,元素入隊的push操作只是制造了該元素的一個副本入隊,因此在入隊后對原元素的修改是不會影響隊列中的副本,同樣的,對隊列中副本的修改也不會改變原元素,需要注意由此可能引入的bug!?

例如下面這個例子:

#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]);}//嘗試直接把隊首元素(即a[1])的數(shù)據(jù)域改為100q.front().data = 100;//事實上對隊列元素的修改無法改變原元素printf("%d %d %d\n", a[1].data, a[2].data, a[3].data);//輸出1 2 3 注意哦,并不是100 2 3//嘗試直接修改a[1]的數(shù)據(jù)域為200(即a[1],上面已經(jīng)修改為100)a[1].data = 200;//事實上對原元素的修改也無法改變隊列中的元素printf("%d\n", q.front().data);//輸出100 注意哦,并不是200return 0; }

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

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

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

?

六、藍橋結語:遇見藍橋遇見你,不負代碼不負卿!

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

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

總結

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

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