LeetCode刷题之BFS算法
LeetCode刷题之BFS算法
1.基本思路及代码框架
BFS算法起源于二叉树的层序遍历,其核心是利用队列这种数据结构。
BFS的核心思想就是把一些问题抽象成图,从一个点开始,向四周扩散。一般来说,我们写BFS算法都是用到队列这种数据结构,每次将一个节点周围的所有节点加入队列。
BFS和DFS最主要的区别就是:BFS找到的路径一定是最短的,但代价就是空间复杂度可能比DFS大很多。
BFS出现的常见情景,就是:问题的本质就是让你在一幅图中找到从起点start到终点target的最近距离,这个例子听起来很枯燥,但是BFS算法问题其实都是在干这个事。基本代码框架如下:
int BFS(Node *start, Mode *target) {
queue<Node*> q; //BFS的核心数据结构队列
set<Node*> visited; //避免走回头路
q.push(start); //将起点加入队列
visited.insert(start);
int step = 0; //往下扩散的步数
while (!q.empty()) {
int sz = q.size();
for (int i = 0; i < sz; i++) { //将当前节点往四周进行扩散
Node *cur = q.front();
if (cur == target) { //判断是否到达终点
return;
}
for (auto x : cur.adj) { //将cur相邻的节点加入队列
if (!visited.count(x)) {
q.push(x);h
visited.insert(x);
}
}
}
step++;//更新步数
}
}
2.题目解答
1.LeetCode之111二叉树的最小深度
-
解题思路
使用广度优先遍历求解,每次向前走一步寻找最小的距离。
-
代码实现
/* * @lc app=leetcode.cn id=111 lang=cpp * * [111] 二叉树的最小深度 */ // @lc code=start /** * 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 minDepth(TreeNode* root) { if (root == nullptr) { return 0; } queue<TreeNode*> q; q.push(root); int depth = 1; while (!q.empty()) { int sz = q.size(); for (int i = 0; i < sz; i++) { TreeNode *node = q.front(); q.pop(); if (node->left == nullptr && node->right == nullptr) { return depth; } if (node->left != nullptr) { q.push(node->left); } if (node->right != nullptr) { q.push(node->right); } } depth++; } return depth; } }; // @lc code=end
2.LeetCode之752打开转盘锁
-
解题思路
可以将此问题抽象成一个图问题,然后采用广度优先遍历进行解决,每一个节点有八个邻节点。
-
代码实现
1.使用单向BFS
/* * @lc app=leetcode.cn id=752 lang=cpp * * [752] 打开转盘锁 */ // @lc code=start class Solution { public: int openLock(vector<string>& deadends, string target) { queue<string> q; set<string> visited; set<string> dead; for (auto h : deadends) { dead.insert(h); } string s("0000"); q.push(s); visited.insert(s); int step = 0; while (!q.empty()) { int sz = q.size(); for (int i = 0; i < sz; i++) { string m = q.front(); q.pop(); if (dead.count(m) == 1) { continue; } if (m == target) { return step; } for (int j = 0; j < 4; j++) { string up = plusOne(m, j); string down = minuOne(m, j); if (visited.count(up) == 0) { q.push(up); visited.insert(up); } if (visited.count(down) == 0) { q.push(down); visited.insert(down); } } } step++; } return -1; } string plusOne(string s, int i) { //将字符串的某一位加一 if (s[i] == '9') { s[i] = '0'; } else { s[i] = s[i] + 1; } return string(s); } string minuOne(string s, int i) { if (s[i] == '0') { s[i] = '9'; } else { s[i] -= 1; } return string(s); } }; // @lc code=end
2.使用双向BFS进行优化
/* * @lc app=leetcode.cn id=752 lang=cpp * * [752] 打开转盘锁 */ // @lc code=start class Solution { public: int openLock(vector<string>& deadends, string target) { set<string> dead; for (auto str : deadends) { dead.insert(str); } set<string> q1; set<string> q2; set<string> visited; int step = 0; q1.insert(string("0000")); q2.insert(target); while(!q1.empty() && !q2.empty()) { set<string> temp; for (auto cur : q1) { if (dead.count(cur)) { continue; } if (q2.count(cur)) { return step; } visited.insert(cur); for (int j = 0; j < 4; j++) { string up = plusOne(cur, j); string down = minuOne(cur, j); if (visited.count(up) == 0) { temp.insert(up); } if (visited.count(down) == 0) { temp.insert(down); } } } step++; q1 = q2; q2 = temp; } return -1; } string plusOne(string s, int i) { //将字符串的某一位加一 if (s[i] == '9') { s[i] = '0'; } else { s[i] = s[i] + 1; } return string(s); } string minuOne(string s, int i) { if (s[i] == '0') { s[i] = '9'; } else { s[i] -= 1; } return string(s); } }; // @lc code=end
3.LeetCode之773滑动谜题
-
解题思路
利用BFS进行暴力穷举,将问题抽象成一个图问题。
-
代码实现
/* * @lc app=leetcode.cn id=773 lang=cpp * * [773] 滑动谜题 */ // @lc code=start class Solution { public: int slidingPuzzle(vector<vector<int>>& board) { int m =2, n = 3; string target = "123450"; //将二维数组转化成一维数组 string start = ""; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { start.push_back(board[i][j] + '0'); } } //记录一维数组的相邻索引 vector<vector<int>> neighbor = { {1, 3}, {0, 4, 2}, {1, 5}, {0, 4}, {3, 1, 5}, {4, 2} }; //BFS算法开始 queue<string> q; set<string> visited; int step = 0; q.push(start); visited.insert(start); while(!q.empty()) { int sz = q.size(); for (int i = 0; i < sz; i++) { string cur = q.front(); q.pop(); if (cur == target) { return step; } int idx = 0; for(; cur[idx] != '0'; idx++); for (auto adj : neighbor[idx]) { string new_board = cur; swap(new_board[idx], new_board[adj]); if (visited.count(new_board) == 0) { q.push(new_board); visited.insert(new_board); } } } step++; } return -1; } }; // @lc code=end