当前位置: 首页 > news >正文

算法 --- 队列 + 宽搜(BFS)

队列 + 宽搜(BFS)

当题目涉及“层级扩展”、“最短路径”或“状态转换的最小步数”时,就应该使用队列+宽搜(BFS)。

队列 + 宽搜(BFS)算法主要适用于解决那些需要按层次遍历或寻找无权图最短路径的问题。其核心思想是从一个起点出发,逐层地、均匀地向所有可能的方向探索,确保第一次到达目标时的路径就是最短的。具体适用于以下几类题目:

  1. 树/图的层级遍历:例如二叉树的层序遍历,或需要按距离起点第K层的所有节点。

  2. 迷宫/网格最短路径:在二维网格中,从起点到终点,避开障碍物,求移动的最小步数(每次可上下左右移动一格)。这是最经典的BFS应用场景。

  3. 最小转换步数问题:题目将一种状态(如一个字符串、一个数组配置)通过一系列规则转换为目标状态,求所需的最小操作次数。例如“滑动谜题”、“打开转盘锁”等,每个状态可以看作图的一个节点,一次操作就是连接节点的边。

  4. 连通块问题:需要找出一个平面或图中所有连通的区域(如岛屿问题),BFS可以有效地遍历并标记整个区域。

为什么用队列?
因为队列“先进先出”(FIFO)的特性完美契合了BFS“先来的先扩展”的需求。它保证了先被访问的节点(离起点更近的层)永远先于后被访问的节点(离起点更远的层)得到处理,从而确保了找到最短路径的正确性。

总结:只要你看到题目要求“最短”、“最少步数”、“按层展开”,你的第一反应就应该是队列+BFS。

基本的框架就是:

XXX bfs (Node* root) {queue<Node*> q;if(root == nullptr) return ???;q.push(root);while(q.size()){// int sz = q.size();vector<int> tmp;//while(sz--)//{Node* t = q.front();q.pop();//}}return ???
}

题目练习

429. N 叉树的层序遍历 - 力扣(LeetCode)

解法:

算法思路:

层序遍历即可~

仅需多加一个变量,用来记录每一层结点的个数就好了。

class Solution {
public:vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> ret;queue<Node*> q;if(root == nullptr) return ret;q.push(root);while(q.size()){int sz = q.size();vector<int> tmp;while(sz--){Node* t = q.front();q.pop();tmp.push_back(t->val);for(Node* child : t->children){if(child) q.push(child);}}ret.push_back(tmp);}return ret;}
};

103. 二叉树的锯齿形层序遍历 - 力扣(LeetCode)

解法(层序遍历):

算法思路:

在正常的层序遍历过程中,我们是可以把一层的结点放在一个数组中去的。

既然我们有这个数组,在合适的层数逆序就可以得到锯齿形层序遍历的结果。

class Solution {
public:vector<vector<int>> zigzagLevelOrder(TreeNode* root) {vector<vector<int>> ret;if(root == nullptr) return ret;queue<TreeNode*> q;q.push(root);bool flag = true;//正序while(q.size()){int sz = q.size();vector<int> tmp;while(sz--){auto t = q.front();q.pop();tmp.push_back(t->val);if(t->left) q.push(t->left);if(t->right) q.push(t->right);}if(!flag) reverse(tmp.begin(), tmp.end());flag = !flag;ret.push_back(tmp);}return ret;}
};

662. 二叉树最大宽度 - 力扣(LeetCode)

解法(层序遍历):

算法思路:

  1. 第一种思路(会超过内存限制):

    既然统计每一层的最大宽度,我们优先想到的就是利用层序遍历,把当前层的结点全部存在队列里面,利用队列的长度来计算每一层的宽度,统计出最大的宽度。

    但是,由于空节点也是需要计算在内的。因此,我们可以选择将空节点也存在队列里面。

    这个思路是我们正常会想到的思路,但是极端情况下,最左边一条长链,最右边一条长链,我们需要存几个空节点,会超过最大内存限制。

  2. 第二种思路(利用二叉树的顺序存储 - 通过根节点的下标,计算左右孩子的下标):

    依旧是利用层序遍历,但是这一次队列里面不单单存结点信息,并且还存储当前结点如果在数组中存储所对应的下标(在我们学习数据结构 - 堆的时候,计算左右孩子的方式)。

    这样我们计算每一层宽度的时候,无需考虑空节点,只需将当层结点的左右结点的下标相减再加 1 即可。

    但是,这里有个细节问题:如果二叉树的层数非常恐怖的话,我们任何一种数据类型都不能存下下标的值。但是没有问题,因为:

    • 我们数据的存储是一个环形的结构;

    • 并且题目说明,数据的范围在 int 这个类型的最大值的范围之内,因此不会超出一圈

    • 因此,如果是求差值的话,我们无需考虑溢出的情况。

class Solution {
public:int widthOfBinaryTree(TreeNode* root) {vector<pair<TreeNode*, unsigned int>> q;q.push_back({root, 1});unsigned int ret = 0;while(q.size()){auto& [x1, y1] = q[0];auto& [x2, y2] = q.back();ret = max(ret, y2 - y1 + 1);vector<pair<TreeNode*, unsigned int>> tmp;for(auto& [x, y] : q){if(x->left) tmp.push_back({x->left, y * 2});if(x->right) tmp.push_back({x->right, y * 2 + 1});}q = tmp;}return ret;}
};

515. 在每个树行中找最大值 - 力扣(LeetCode)

解法(BFS):

算法思路:

层序遍历过程中,在执行让下一层节点入队的时候,我们是可以在循环中统计出当前层结点的最大值的。

因此,可以在 BFS 的过程中,统计出每一层结点的最大值。

class Solution {
public:vector<int> largestValues(TreeNode* root) {vector<int> ret;if(root == nullptr) return ret;queue<TreeNode*> q;q.push(root);while(q.size()){int sz = q.size();int tmp = INT_MIN;while(sz--){auto t = q.front();q.pop();tmp = max(tmp, t->val);if(t->left) q.push(t->left);if(t->right) q.push(t->right);}ret.push_back(tmp);}return ret;}
};


文章转载自:

http://sAbF2VaA.qyqmj.cn
http://GgcbEEfv.qyqmj.cn
http://LxJ4Wlq7.qyqmj.cn
http://3dJBvBTo.qyqmj.cn
http://4WoQ1pne.qyqmj.cn
http://C5pYdakJ.qyqmj.cn
http://x3nVWTWO.qyqmj.cn
http://m7NQKtYd.qyqmj.cn
http://uxVZTsqs.qyqmj.cn
http://K0DnNeND.qyqmj.cn
http://vxgBy5P4.qyqmj.cn
http://JbLa4QLP.qyqmj.cn
http://dpCawTgO.qyqmj.cn
http://5GsGyh8e.qyqmj.cn
http://UHQghyq0.qyqmj.cn
http://bANCGEu5.qyqmj.cn
http://X4XqNUWH.qyqmj.cn
http://zWE93sVQ.qyqmj.cn
http://sVX9Fu1G.qyqmj.cn
http://7pqf6Okp.qyqmj.cn
http://3QJW0kDE.qyqmj.cn
http://GWBVec7d.qyqmj.cn
http://8WVmt0nX.qyqmj.cn
http://uzxIVvva.qyqmj.cn
http://VEytvtuP.qyqmj.cn
http://I8OlKd5M.qyqmj.cn
http://8dnz7zrA.qyqmj.cn
http://Fn9L0CW1.qyqmj.cn
http://aM48VuAS.qyqmj.cn
http://697lfCr5.qyqmj.cn
http://www.dtcms.com/a/387296.html

相关文章:

  • 苹果手机怎么导出App数据目录,iOS文件管理、应用沙盒访问、日志缓存导出与性能调试实战(uni-app开发者指南)
  • Java 设计模式——策略模式:从 3 种写法到 SpringBoot 进阶
  • JVM:性能调优的理解
  • AR眼镜在巡检业务中的软件架构设计|阿法龙XR云平台
  • 活动预告 | Paraverse × Unity:Unity云XR串流——突破设备与平台限制
  • 第十四届蓝桥杯青少组C++选拔赛[2022.12.18]第二部分编程题(5、猴子拿桃)
  • 二维码辅助回桩之二维码识别
  • Mojo vs Python vs Rust,2025年搞AI,怎么学
  • 从软件工程角度谈企业管理
  • 【C语言】C 语言自定义类型:联合与枚举的基础解析
  • 模型部署:(五)安卓端部署Yolov8关键点检测项目全流程记录
  • 在业务应用中集成 go-commons,实现应用+系统双指标监控
  • ESP32-C3四种工作模式
  • ReactNative中实现可拖拽的温度计组件
  • react snippets
  • 基于Matlab高低频混合建模的大气湍流相位屏生成算法
  • 2025年8月SCI-袋鼠逃生优化算法Kangaroo Escape Optimizer-附Matlab免费代码
  • Node.js 创建 TCP 服务
  • 关于鸿蒙配置HMRouter的问题,比如白屏等
  • 为什么 socket.io 客户端在浏览器能连接服务器但在 Node.js 中报错 transport close?
  • Express框架介绍(基于Node.js的轻量级、灵活的Web应用框架)
  • Lustre Ceph GlusterFS NAS 需要挂载在k8s容器上,数据量少,选择哪一个存储较好
  • Axios与Java Spring构建RESTful API服务集成指南
  • 贪心算法应用:集合覆盖问题详解
  • 分布式拜占庭容错算法——权益证明(PoS)算法详解
  • Maven 深入profiles和mirrors标签
  • SQL Server 运维实战指南:从问题排查到性能优化
  • FFmpeg的安装及简单使用
  • F019 vue+flask海外购商品推荐可视化分析系统一带一路【三种推荐算法】
  • R语言数据统计分析与ggplot2高级绘图实践应用