广度优先(BFS)

1 广度优先简介

常常使用队列来配合解决。

2 力扣题目

2.1 二叉树的最小深度

111. 二叉树的最小深度

迭代版本:

/**
 * 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 矩阵中的距离

剑指 Offer II 107. 矩阵中的距离

542. 01 矩阵

/*广度优先:以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 打开转盘锁

752. 打开转盘锁

剑指 Offer II 109. 开密码锁

// 双向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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值