1 广度优先简介
常常使用队列来配合解决。
2 力扣题目
2.1 二叉树的最小深度
迭代版本:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int minDepth(TreeNode* root) {
if (!root)
{
return 0;
}
queue<TreeNode*> q;
q.push(root);
//root本身就是一层,所以初始化为1
int minDep = 1;
while (!q.empty())
{
int sz = q.size();
//将当前队列中的所有节点向四周扩散
for (int i = 0;i < sz; ++i)
{
TreeNode *cur = q.front();
q.pop();
//判断是否到达终点
if (!cur->left && !cur->right)
{
return minDep;
}
//将cur相邻的节点加入队列
if (cur->left)
{
q.push(cur->left);
}
if (cur->right)
{
q.push(cur->right);
}
}
//这里增加步数
++minDep;
}
return minDep;
}
};
递归版本:
/**
* 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)
{
return 0;
}
if (!root->left)
{
return 1 + minDepth(root->right);
}
else if (!root->right)
{
return 1 + minDepth(root->left);
}
else
{
return 1 + std::min(minDepth(root->left), minDepth(root->right));
}
}
};
2.2 矩阵中的距离
/*广度优先:以0为中心向四周进行扩展
广度优先搜索需要使用一个队列,因为题目中需要求每个格子距离 0 的最短距离,
可以考虑把所有为 0 的格子作为初始节点添加到队列中,然后以这些点为起点开始广度搜索。
队列的初始节点为格子为 0 的节点,若这些节点在出列时该格子周围没有 1 格子,则其四周的格子不会加入队列,
故由初始节点出列而加入队列的第一批格子就是距离 0 的最近距离为 1 的格子,那么由第一批格子出队列而加入队列的
第二批格子就是距离 0 的最近距离为 2 的格子。依次类推,所以后加入的格子确定的距离不可能小于之前的。
*/
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
int n = mat.size(), m = mat[0].size();
vector<vector<int>> distance(n, vector<int>(m, INT_MAX));
queue<pair<int,int>> q;
vector<pair<int, int>> neighbour({ {-1,0},{1,0},{0,-1},{0,1} });
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
if (!mat[i][j])
{
distance[i][j] = 0;
q.push(make_pair(i,j));
}
}
}
while(!q.empty())
{
auto pos = q.front();
q.pop();
int dist = distance[pos.first][pos.second];
for(auto& item : neighbour)
{
int r = pos.first + item.first;
int c = pos.second + item.second;
if (r >= 0 && r < mat.size() && c >= 0 && c < mat[0].size())
{
if (distance[r][c] > 1 + dist)
{
distance[r][c] = 1 + dist;
q.push(make_pair(r,c));
}
}
}
}
return distance;
}
};
2.3 打开转盘锁
// 双向BFS
class Solution {
public:
int openLock(vector<string>& deadends, string target) {
//记录需要跳过的死亡密码
unordered_set<string> deads(deadends.begin(), deadends.end());
//记录已经穷举过的密码,防止走回头路
unordered_set<string> visited;
//用集合而不用队列,可以快速判断元素是否存在
unordered_set<string> q1, q2;
//从起点开始启动广度优先搜索
int step = 0;
q1.insert("0000");
q2.insert(target);
while (!q1.empty() && !q2.empty())
{
//哈希集合在遍历过程中不能修改,故此处用temp来存储扩散结果
unordered_set<string> temp;
//将当前队列中的所有节点向周围扩散
for (auto& cur : q1)
{
//判断是否到达终点
if (deads.count(cur))
{
continue;
}
if (q2.count(cur))
{
return step;
}
visited.insert(cur);
//将一个节点的未遍历的相邻节点加入到队列中
for (int j = 0; j < 4; ++j)
{
string up = plusOne(cur, j);
if (!visited.count(up))
{
temp.insert(up);
}
string down = minusOne(cur, j);
if (!visited.count(down))
{
temp.insert(down);
}
}
}
//在这里增加步数
++step;
//保证待遍历的q1中始终含有较少的元素
if (q2.size() < temp.size())
{
q1.swap(q2);//q1 = q2;
q2.swap(temp);//q2 = temp;
}
else
{
q1.swap(temp);//q1 = temp;
}
}
//如果穷举完都没有找到目标密码,则返回-1
return -1;
}
string plusOne(const string& s, int j)
{
string tmp(s);
if (tmp[j] == '9')
{
tmp[j] = '0';
}
else
{
tmp[j] += 1;
}
return tmp;
}
string minusOne(const string& s, int j)
{
string tmp(s);
if (tmp[j] == '0')
{
tmp[j] = '9';
}
else
{
tmp[j] -= 1;
}
return tmp;
}
};
2.4