【基础算法总结】队列 + 宽搜(BFS)

队列 + 宽搜BFS

  • 1.N 叉树的层序遍历
  • 2.二叉树的锯齿形层序遍历
  • 3.二叉树最大宽度
  • 4.在每个树行中找最大值

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.N 叉树的层序遍历

题目链接: 429. N 叉树的层序遍历

题目分析:

在这里插入图片描述

层序遍历是一层一层的出,需要借助队列使用BFS来完成。比如说遍历到第三层的时候需要从第二层第一个节点的孩子先开始。因此就需要先记录这个节点的信息,遍历完3、4、5回过头再来遍历3的孩子。符合先进先出的思想。所以层序遍历要用到队列来实现。

在这里插入图片描述

算法原理:

解法:BFS(层次遍历/宽度优先搜索/宽度优先搜索)

层序遍历步骤,先搞一个队列,如果根节点不为空,现让根节点入队。接下来就是一个循环,当队列不空的时候,先把队头元素拿出来,然后把队头元素的孩子入队。循环下去直到队列为空为止。就把这棵树层序遍历结束了。

但是这道题要求的是一层一层出,因此我们需要一个变量在每次出队之前先统计一下当前队列中有多少个元素,然后每次出这一层的个数就行了。这个变量就是当前这一层元素的个数。

在这里插入图片描述

/*
// Definition for a Node.
class Node {
public:int val;vector<Node*> children;Node() {}Node(int _val) {val = _val;}Node(int _val, vector<Node*> _children) {val = _val;children = _children;}
};
*/class Solution {
public:vector<vector<int>> levelOrder(Node* root) {vector<vector<int>> ret; //记录最终结果if(root == nullptr) return ret;queue<Node*> qu;//层序遍历需要的队列qu.push(root);while(!qu.empty()){int num = qu.size();//先统计出本层元素的个数vector<int> tmp; //统计本层的节点while(num--){Node* front = qu.front();tmp.push_back(front->val);qu.pop();for(auto* cur : front->children)//下一层入队{qu.push(cur);}}ret.push_back(tmp);      }return ret;}
};

2.二叉树的锯齿形层序遍历

题目链接: 103. 二叉树的锯齿形层序遍历

题目分析:

在这里插入图片描述
锯齿形层序遍历 ,先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行
在这里插入图片描述

算法原理:

解法:BFS

这道题和上面是一模一样的,只不过有一点小小的改变。发现偶数列是逆序放的。因此可以增加一个标记位,让偶数列的信息逆序即可。

/*** 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>> zigzagLevelOrder(TreeNode* root) {vector<vector<int>> ret;if(root == nullptr) return ret;queue<TreeNode*> qu;qu.push(root);int level = 1;while(!qu.empty()){int k = qu.size();vector<int> tmp;while(k--){TreeNode* t = qu.front();qu.pop();tmp.push_back(t->val);if(t->left) qu.push(t->left);if(t->right) qu.push(t->right);}if(level % 2 == 0) reverse(tmp.begin(),tmp.end());ret.push_back(tmp);++level;}return ret;}
};

3.二叉树最大宽度

题目链接:662. 二叉树最大宽度

题目分析:

在这里插入图片描述

每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。

最左和最右非空节点中间的nullptr也要加入计算到长度。
在这里插入图片描述

算法原理:

解法一:硬来

依旧是创建一个队列,这次入队不一样即使是一个节点的左孩子或者右孩子是null也要入队。然后在每一层出队之前都可以统计这一层有多宽。比如这棵树第三层没有问题宽度就是这一层的节点数,但是第四层就有问题了,实际宽度并不是这一层节点数。那如何统计这一层的实际宽度呢?方法很简单,我们在遍历这一层的时候可以再来一个empty指针,当这个指针遇到不是 null 的时候 宽度+1,如果是空的话就统计就循环把null拿到,如果碰到非空的时候就把 null 的个数 加入到 宽度,然后把null 的个数记为0。如果直到遍历到队列结尾还没有碰到非空 就不要把 null 结点数加入到 宽度。

在这里插入图片描述

但是这个方法会超时!
在这里插入图片描述

虽然节点有1-3000个,但是如果是系啊没这种左右非常平均有1500个节点。最后一层一共2^1499个节点,那太恐怖了。内存根本放不下。

在这里插入图片描述

接下来我们换一种策略。

树不仅可以用链式存储,也可以用数组存储起来,例如堆。

解法二:利用数组存储二叉树的方式,给结点编号

对一个结点i,如何找它的左右孩子,有两种方法如下:

在这里插入图片描述
有这个启发之后,那为何不给树每个结点都加上一个编号,孩子是null结点就不用在放入队列了,队列中只存储有孩子的结点和编号,然后这一层把第一个结点的编号和最后一个结点的编号拿出来,然后 最后一个结点的编号 减去 第一个结点的编号 + 1 不就是这一层宽度吗!

queue<pair<TreeNode*,int>>

还是这一层出队之前把第一个结点和最后一个结点拿到,取出里面的编号,做对应的计算。 如 7 - 4 + 1 = 4,14 - 8 + 1 = 7。比较每层宽度取最大的宽度。
在这里插入图片描述

上面是用队列来做的,甚至可以不用队列,就用两个数组就可以模拟队列。因此
vector<pair<TreeNode*,int>> 也是可以的。

这里还有一个细节问题:下标有可能会溢出。还是刚才的例子,左边来1500个节点,右边来1500个节点。最后一个节点编号是2^1500 - 1,不管用什么类型都存不下!别说这里int,甚至double都不行。

在这里插入图片描述

难道要用字符串来存,然后做高精度加减吗,其实也不用, 因为我们最后是做减法的,即使溢出,但是相减的结果也是正确的。

我们的数据存储其实是可以看作一个环,如char -128 ~ 127
虽然正数会溢出到负数, 但是 我们做减法求的是两个数之间的距离,当两个数相减就会把结果修正,因为求的是之间的距离,这段距离是正的并且不会溢出。

但是前提不能是超过一圈然后到的这个位置。此时减肯定是一个错误。但是这道题告诉题目数据保证答案将会在 32 位 带符号整数范围内。因此pair 内 int 换成 unsigned int

vector<pair<TreeNode*,unsigned int>>

在这里插入图片描述

/*** 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 widthOfBinaryTree(TreeNode* root) {queue<pair<TreeNode*,unsigned int>> qu;unsigned int ret = 0;if(root == nullptr) return ret;qu.push(make_pair(root,1));while(!qu.empty()){   //先更新这一层的宽度//pari对象里面的成员会分别存到 first -> x1, second -> y1auto& [x1,y1] = qu.front();auto& [x2,y2] = qu.back();ret = max(ret, y2 - y1 + 1);//让下一层入队int k = qu.size();while(k--){auto [x,y] = qu.front();qu.pop();if(x->left) qu.push(make_pair(x->left,2 * y));if(x->right) qu.push(make_pair(x->right,2 * y +1));}}return ret;}
};

数组模拟队列

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;}
};

4.在每个树行中找最大值

题目链接:515. 在每个树行中找最大值

题目描述:

在这里插入图片描述

算法原理:

解法:利用层序遍历,统计出每一层的最大值

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3266777.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

配置web服务器练习

4练习要求&#xff1a; 练习一&#xff1a;配置web服务器&#xff0c;当访问网站 www.haha.com 时显示&#xff1a;haha 练习二&#xff1a;配置web服务器&#xff0c;当访问网站 www.xixi.com/secret/ 时显示&#xff1a;this is secret 具体步骤&#xff1a; 1、配置yum…

go程序在windows服务中优雅开启和关闭

本篇主要是讲述一个go程序&#xff0c;如何在windows服务中优雅开启和关闭&#xff0c;废话不多说&#xff0c;开搞&#xff01;&#xff01;&#xff01;   使用方式&#xff1a;go程序 net服务启动 Ⅰ 开篇不利 Windows go进程编译后&#xff0c;为一个.exe文件,直接执行即…

docker挂载部署reids6.2.1

1.拉取镜像 docker pull redis:6.2.12.创建挂在目录&#xff08;根据自己要求修改具体目录&#xff09; mkdir -p /home/admin/redis/{data,conf}3.在/home/admin/redis/conf目录下创建redis.conf文件 cd /home/admin/redis/conf touch redis.conf4.复制下面文本到redis.conf…

实时同步:使用 Canal 和 Kafka 解决 MySQL 与缓存的数据一致性问题

目录 1. 准备工作 2. 将需要缓存的数据存储 Redis 3. 监听 canal 存储在 Kafka Topic 中数据 1. 准备工作 1. 开启并配置MySQL的 BinLog&#xff08;MySQL 8.0 默认开启&#xff09; 修改配置&#xff1a;C:\ProgramData\MySQL\MySQL Server 8.0\my.ini log-bin"HELO…

数据库练习——编写触发器及存储过程

1. 触发器 建立两个表:goods(商品表)、orders(订单表) 在商品表中导入商品记录 mysql> create database mydb16_trigger; Query OK, 1 row affected (0.00 sec)mysql> use mydb16_trigger; Database changed mysql> create table goods(-> gid char(8) primary …

系统架构师(每日一练7)

每日一练 1.关于网络延迟正确的是()。答案与解析 A.在对等网络中&#xff0c;网络的延迟大小与网络中的终端数量无关 B.使用路由器进行数据转发所带来的延迟小于交换机, C.使用internet服务器可最大程度地减小网络延迟 D.服务器延迟的主要影响因素是队列延迟和磁盘10延迟 2.以…

idea中项目目录,文件显示不全问题

问题&#xff1a;idea中项目目录显示不全问题 解决办法1&#xff1a; 删除目录中的.idea文件 用idea重新打开文件就行了 办法2&#xff1a;手动导入为maven项目 1. 2. 3. 4.选择要导入的项目&#xff0c;导入为maven

【网络流】——初识(最大流)

网络流-最大流 基础信息引入一些概念基本性质 最大流定义 Ford–Fulkerson 增广Edmons−Karp算法Dinic 算法参考文献 基础信息 引入 假定现在有一个无限放水的自来水厂和一个无限收水的小区&#xff0c;他们之间有多条水管和一些节点构成。 每一条水管有三个属性&#xff1a…

重拾CSS,前端样式精读-函数(颜色,计算,图像和图形)

前言 本文收录于CSS系列文章中&#xff0c;欢迎阅读指正 在计算机编程中&#xff0c;函数有着重要的作用和意义&#xff0c;它可以实现封装&#xff0c;复用&#xff0c;模块化&#xff0c;参数等功能效果&#xff0c;在如何在CSS中写变量&#xff1f;一文带你了解前端样式利…

AI学习记录 - 图像识别的基础入门

代码实现&#xff0c;图像识别入门其实非常简单&#xff0c;这里使用的是js&#xff0c;其实就是把二维数组进行公式化处理&#xff0c;处理方式如上图&#xff0c;不同的公式代表的不同的意义&#xff0c;这些意义网上其实非常多&#xff0c;这里就不细讲了。 const getSpecif…

【YOLOv8系列】图像分类篇----通过YOLOv8实现图像分类功能

最近需要使用YOLOv8对自己的数据集进行训练,从而实现图像分类的功能,因此记录一下整个过程。 YOLOv8的github地址:https://github.com/ultralytics/ultralytics 参考链接:超详细YOLOv8图像分类全程概述:环境、训练、验证与预测详解 文章目录 一、YOLOv8环境搭建二、准备…

电脑QQ录屏功能怎么用?图文教程,轻松掌握电脑录屏

“想问一下大家知道电脑QQ录屏功能怎么打开吗&#xff1f;一直以来我使用电脑QQ截图非常方便&#xff0c;但不知道原来QQ还有录屏功能。希望知道QQ录屏功能使用方法的朋友教一下我好吗&#xff1f;” 今天&#xff0c;就让我带大家一起探索电脑QQ录屏功能怎么用&#xff1f;看…

怎么注册自己的电子邮件地址

无论是在职场上的工作沟通、日常的在线购物、或是订阅各类新闻资讯&#xff0c;电子邮件都是您不可或缺的数字化工具。本文将手把手引导您完成注册过程&#xff0c;从选择服务商到完成所有必要步骤&#xff0c;帮助您轻松拥有自己的电子邮件账户。 一、选择电子邮件服务商 市…

友盟U-APM——优秀的前端性能监控工具

在数字化转型浪潮的推动下,移动应用已成为企业连接用户、驱动业务增长的核心载体。然而,随着应用复杂度的日益提升,用户对于应用性能稳定性的期待也水涨船高。面对应用崩溃、卡顿、加载缓慢等频发问题,如何确保应用的流畅运行,成为产研团队亟待解决的关键挑战。在此背景下,友盟…

常见的CSS属性(一)——字体、文本、边框、内边距、外边距、背景、行高、圆角、透明度、颜色值

一、字体 二、文本 三、边框 四、外边距 五、内边距 六、背景 七、行高 八、圆角 九、透明度 九、颜色值 元素的继承性是指给父元素设置了某些属性&#xff0c;子元素或后代元素也会有作用。 一、字体 “font-*”是字体相关的属性&#xff0c;具有继承性。代码如下&a…

浅谈监听器之简单数据写入

浅谈监听器之简单数据写入 “简单数据写入”&#xff08;Simple Data Writer&#xff09;监听器便是其中之一&#xff0c;它提供了一种简便的方式来将测试结果直接输出到文件中&#xff0c;便于后续的数据分析与处理。 简单数据写入监听器概述 “简单数据写入”监听器&#…

pdf压缩在线免费 pdf压缩在线免费网页版 在线pdf压缩在线免费 免费pdf压缩工具 压缩到最小几种方法详细步骤分享

PDF是当前最为常见的电子文档格式&#xff0c;它可以保护文档不被篡改或复制格式可以保持原格式。然而&#xff0c;因为市面上积攒的PDF文件数量过多&#xff0c;也容易因为体积太大的缘故&#xff0c;致使后面对磁盘存储造成很大的压力&#xff0c;压缩PDF文件能有效缩小其体积…

海上导航技术介绍

导航的目的主要是帮助人们或设备确定自己在地理空间中的位置&#xff0c;从而能够引导飞机、舰船、车辆等沿着设定路线安全、准确地到达目的地。 导航可以提供两类信息&#xff1a;第一类信息为载体自身的运动参数&#xff0c;如用户自己的三维坐标和速度矢量、航向、姿态等信…

【python】PyQt5中QPushButton的用法详细解析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

苍穹外卖浏览器前端界面修改

背景&#xff1a; 客户原始方案是期望做一个Spring Boot Vue的饿了么系统&#xff0c;但时间上太仓促&#xff0c;所以建议选择开源的苍穹外码目作为作业提交。 客户接受了建议的方案后&#xff0c;期望对前端页面做一些个性化的定制修改。 过程&#xff1a; 苍穹外卖简单介…