算法通关村第六关—二叉树的层次遍历经典问题(白银)

         二叉树的层次遍历经典问题

一、层次遍历简介

广度优先遍历又称层次遍历,过程如下:截屏2023-12-01 13.05.51.png
 层次遍历就是从根节点开始,先访问根节点下面一层全部元素,再访问之后的层次,图里就是从左到右一层一层的去遍历二叉树,先访问3,之后访问的左右子孩子9和20,之后分别访问9和20的左右子孩子[8,13]和[15,17],最后得到结果[3,9,20,8,13,15,17]。
 这里的问题是怎么将遍历过的元素的子孩子保存一下呢,例如访问9时其左右子孩子8和13应该先存一下,直到处理20之后才会处理。使用队列来存储能完美解决上述问题,例如上面的图中:
截屏2023-12-01 13.08.13.png
 思考:该过程不复杂,如果能将树的每层次分开了,是否可以整点新花样?首先,能否将每层的元素顺序给反转一下呢?能否奇数行不变,只将偶数行反转呢?能否将输出层次从低到root逐层输出呢?再来,既然能拿到每一层的元素了,能否找到当前层最大的元素?最小的元素?最右的元素(右视图)?最左的元素(左视图)?整个层的平均值?
 很明显都可以!这么折腾有啥用呢?没啥用!但这就是层次遍历的高频算法题!这就是LeetCode里经典的层次遍历题!
102.二叉树的层序遍历
107.二叉树的层次遍历II
199.二叉树的右视图
637.二叉树的层平均值
429.N叉树的前序遍历
515.在每个树行中找最大值
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针l
103锯齿层序遍历
除此之外,在深度优先的题目里,有些仍然会考虑层次遍历的实现方法。

二、基本的层序遍历与变换

2.1 层序遍历基础版

最简单的情况:仅仅层序遍历并输出所有元素
利用前面讲到的借助队列的方法来实现

List<Integer>simpleLevelorder(TreeNode root){if(root == null){return new ArrayList<Integer>();}List<Integer>res = new ArrayList<Integer>();LinkedList<TreeNode> queue = new LinkedList<TreeNode>();//将根节点放入队列中,然后不断遍历队列queue.add(root);//有多少元素执行多少次while (queue.size()>0){//获取当前队列的长度,这个长度相当于当前这一层的节点个数TreeNode t = queue.remove();res.add(t.val);if(t.left != null){queue.add(t.left);}if(t.right = null){queue.add(t.right);}}return res;
}

2.2 二叉树的层序遍历(模版:非常重要)

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c23f7ece838341c491b3918718f405e5.pn
LeetCode102:给你一个二叉树,请你返回其按层序遍历得到的节点值。(即逐层地,从左到右访问所有节点)。
注意:与前面相比,要区分每一层
截屏2023-12-01 13.24.31.png
如何判断某一层遍历完了?可以设定一个size变量来标记。size表示某一层的元素个数,只要元素出队,size-1.当size==0时,该层已经遍历完了。(代码里的做法与这里殊途同归)
然后此时队里的元素个数为下一层元素的个数,因此让size标记为下一层的元素个数即可处理下一层了。
最后,把每一层遍历到的结点放入一个结果集中,将其返回即可

class Solution {public List<List<Integer>> levelOrder(TreeNode root) {if(root == null) return new ArrayList<List<Integer>>();//创建集合和队列List<List<Integer>> list = new ArrayList<>();LinkedList<TreeNode> queue = new LinkedList();//将根结点放入队列,方便进入循环queue.add(root);while(queue.size() > 0){//everylist集合用来记录某一层的所有元素List<Integer> everylist = new ArrayList<>();//size记录某一层的元素个数int size = queue.size();//从队头遍历某一层的所有元素,并把下一层的元素存放到队尾for(int i = 0; i < size; i++){TreeNode t = queue.remove();everylist.add(t.val);if(t.left != null)queue.add(t.left);if(t.right != null)queue.add(t.right);}//此时i == size,该层所有元素都遍历完了list.add(everylist);}return list;}
}

2.3 层序遍历-自底往上

LeetCode107.给定一个二叉树,返回其节点值自底向上的层序遍历。(即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)。例如给定的二叉树与结果为下图:
截屏2023-12-01 15.06.52.png 截屏2023-12-01 15.07.00.png
实现的代码几乎与正常的层序遍历相同,只在list.add(0,everylist)这里把后面遍历的层次放到list的前面,实现自底往上的效果。

为了降低在结果列表的头部添加一层节点值的列表的时间复杂度,结果列表可以使用链表的结构,即创建list时把ArrayList改成LinkedList。在链表头部添加一层节点值的列表的时间复杂度是O(1)。

class Solution {public List<List<Integer>> levelOrderBottom(TreeNode root) {if(root == null) return new LinkedList<List<Integer>>();List<List<Integer>> list = new LinkedList<>();LinkedList<TreeNode> queue = new LinkedList();queue.add(root);while(queue.size() > 0){List<Integer> everylist = new ArrayList<>();int size = queue.size();for(int i = 0; i < size; i++){TreeNode t = queue.remove();everylist.add(t.val);if(t.left != null)queue.add(t.left);if(t.right != null)queue.add(t.right);}list.add(0,everylist);}return list;}
}

2.4 二叉树的锯齿形层次遍历

LeetCode103题,要求是:给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:给定二叉树[3,9,20,nul,null,15,7]
截屏2023-12-01 15.16.43.png 截屏2023-12-01 15.16.50.png
依旧是对2.2对代码进行改写。因为这里有时是从左到右,有时是从右到左,自然可以想到把代码里的队列改成双端队列,然后再设置过参数判断元素存放位置。
如果从左至右,我们每次将被遍历到的当前层元素插入至双端队列的末尾。如果从右至左,我们每次将被遍历到的元素插入至双端队列的头部。

class Solution {public List<List<Integer>> zigzagLevelOrder(TreeNode root) {if(root == null) return new ArrayList<List<Integer>>();List<List<Integer>> list = new LinkedList<>();Queue<TreeNode> queue = new LinkedList();queue.add(root);Boolean judgeleft = true;while(queue.size() > 0){//创建成双端队列Deque<Integer> everylist = new LinkedList<>();int size = queue.size();for(int i = 0; i < size; i++){TreeNode t = queue.remove();//从左到右放队尾if(judgeleft) everylist.offerLast(t.val);//从右到左放队首else everylist.offerFirst(t.val);if(t.left != null)queue.add(t.left);if(t.right != null)queue.add(t.right);}judgeleft = !judgeleft;//把双端队列转类型list.add(new LinkedList<Integer>(everylist));}return list;}
}

2.5 N叉树的层序遍历

LeetCode.429给定一个N叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)树的序列化输入是用层序遍历,每组子节点都由null值分隔(参见示例)
截屏2023-12-01 17.55.43.png
N叉树的定义如下,就是一个值,加一个列表,其类型仍然是Node:截屏2023-12-01 17.55.52.png
这个也是102的扩展,很简单的广度优先,与二叉树的层序遍历基本一样,借助队列即可实现。只有在保存当前结点的孩子时,不是左右孩子,有N个,可以使用增强for循环来遍历

class Solution {public List<List<Integer>> levelOrder(Node root) {if(root == null)return new ArrayList<List<Integer>>();List<List<Integer>> list = new ArrayList();Queue<Node> queue = new LinkedList();queue.add(root);while(queue.size() > 0){List<Integer> everylist = new ArrayList();int size = queue.size();for(int i = 0; i < size; i++){Node t = queue.remove();everylist.add(t.val);//与2.2唯一不同之处,利用增强for循环遍历所有孩子for(Node node1: t.children) {if(node1 != null) queue.add(node1);}}list.add(everylist);}return list;}
}

三、几个处理每层元素的题目

如果我们拿到了每一层的元素,那是不是可以利用一下造几个题呢?例如每层找最大值、平均值、最右侧的值呢?当然可以。LeetCode.里就有三道非常明显的题目。
515.在每个树行中找最大值
637.二叉树的层平均值
199.二叉树的右视图

3.1 在每个树行中找最大值

LeetCode515题目要求:给定一棵二叉树的根节点root,请找出该二叉树中每一层的最大值。
截屏2023-12-01 18.04.21.png
与模版相比,在while循环中不需要创建另外一个集合,只需要用max记录最大值,然后添加进list集合即可

class Solution {public List<Integer> largestValues(TreeNode root) {if(root == null) return new ArrayList<Integer>();List<Integer> maxlist = new ArrayList();Queue<TreeNode> queue = new LinkedList();queue.add(root);while(queue.size() > 0){int max = Integer.MIN_VALUE;int size = queue.size();for(int i = 0; i < size; i++){TreeNode t =queue.remove();max = Math.max(max,t.val);if(t.left != null) queue.add(t.left);if(t.right != null) queue.add(t.right);}maxlist.add(max);}return maxlist;}
}

3.2 在每个树行中找平均值

LeetCode637要求给定一个非空二叉树,返回一个由每层节点平均值组成的数组
这些题目其实都差不多一个思路,只要中间一些处理修改一下就行。这道题就把每层元素的和记录下来,除以元素个数就行

class Solution {public List<Double> averageOfLevels(TreeNode root) {List<Double> list = new ArrayList();if(root == null) return list;Queue<TreeNode> queue = new LinkedList();queue.add(root);while(queue.size() > 0){int size = queue.size();double sum = 0;for(int i = 0; i < size; i++){TreeNode t = queue.remove();sum += t.val;if(t.left != null) queue.add(t.left);if(t.right != null) queue.add(t.right);}list.add(sum/size);}return list;}
}

3.3 二叉树的右视图

LeetCode199题目要求是:给定一个二叉树的根节点root,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。例如:
截屏2023-12-01 22.22.05.png
这道题只要把每层最后一个元素保存起来即可

class Solution {public List<Integer> rightSideView(TreeNode root) {List<Integer> list = new ArrayList<>();if(root == null) return list;Queue<TreeNode> queue = new LinkedList();queue.add(root);while(queue.size() > 0){int size = queue.size();for(int i = 0; i < size; i++){TreeNode t = queue.remove();if(size - 1 == i) list.add(t.val);if(t.left != null) queue.add(t.left);if(t.right != null) queue.add(t.right);}}return list;}
}

3.4 最底层最左边

上面这个层次遍历的思想可以方便的解决LeetCode513.二叉树最底层最左边的值的问题:给定一个二叉树的根节点root,请找出该二叉树的最底层最左边节点的值。假设二叉树至少有一个节点。
截屏2023-12-01 22.26.25.png截屏2023-12-01 22.26.32.png
如果是正常遍历,是从左到右,那最后会遍历到最底层最右边,与题目正好相反。所以,我们在遍历存储下一层元素的时候,可以先保存右边的节点,再保存左边的节点。这样,遍历就是从右到左,题目就解出来啦。

class Solution {public int findBottomLeftValue(TreeNode root) {//可以记录值;也可记录节点,最后返回值int num = 0;Queue<TreeNode> queue = new LinkedList();queue.add(root);while(queue.size() > 0){int size = queue.size();for(int i = 0; i < size; i++){TreeNode t = queue.remove();num = t.val;if(t.right != null) queue.add(t.right);if(t.left != null) queue.add(t.left);}}return num;}
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学习笔记8——JUC入门基础知识

学习笔记系列开头惯例发布一些寻亲消息 链接&#xff1a;https://baobeihuijia.com/bbhj/contents/3/199561.html 进程和线程:进程是资源分配的最小单位&#xff0c;线程是CPU调度的最小单位 进程和线程的主要区别&#xff08;总结&#xff09;_进程和线程的区别-CSDN博客进程…

Flink的部署模式和运行模式

集群角色 Flink提交作业和执行任务&#xff0c;需要几个关键组件&#xff1a; 客户端&#xff1a;代码由客户端获取并作转换&#xff0c;之后提交给Jobmanager Jobmanager就是Flink集群的管事人&#xff0c;对作业进行中央调度管理&#xff1b;当从客户端获取到转换过的作业后…

NRF24L01 无线收发模块与 Arduino 的应用

NRF24L01 是一款常用的无线收发模块&#xff0c;与 Arduino 兼容性良好&#xff0c;可以用于实现无线通信和数据传输。本文将介绍如何将 NRF24L01 模块与 Arduino 配合使用&#xff0c;包括硬件的连接和配置&#xff0c;以及相应的代码示例。 一、引言 NRF24L01 是一款基于 2.…

CentOS或RHEL安装vscode

下载rpm安装包 网络下载或者下载到本地再上传到服务器&#xff0c;点击访问国内下载地址&#xff0c;不需要积分curl -fOL https://github.com/coder/code-server/releases/download/v4.19.1/code-server-4.19.1-amd64.rpm安装 rpm -i code-server-4.19.1-amd64.rpm关闭和禁用…

STM32F407-14.3.9-01输出比较模式

输出比较模式 此功能用于控制输出波形&#xff0c;或指示已经过某一时间段。 当捕获/比较寄存器与计数器之间相匹配时&#xff0c;输出比较功能&#xff1a; ● 将为相应的输出引脚分配一个可编程值&#xff0c;该值由输出比较模式&#xff08;TIMx_CCMRx 寄存器中的 OCxM⑦…

Python批量Git Pull,对文件夹批量进行Pull操作

效果展示 说明 本来是想写的完善一些&#xff0c;但由于是自用&#xff0c;所以写出来后发现已经解决了自己的问题&#xff0c;所有 2和3功能没有写。 执行的话&#xff0c;需要 cmd 之后 直接 Python BatchGitPull.py 运行下面代码即可。 里面同时涉及到其他Pyhon知识点(写给…

Ubuntu18.04 Udacity project_9_PID_control 如何运行

工程源码和仿真器下载&#xff1a; 源码 仿真器 --- Ubuntu就下载 term2_sim_linux.zip 这个压缩文件即可 紧接着给方框中的文件赋可执行权限 打开project_9_PID_control文件夹 执行如下脚本&#xff0c;安装必要的库&#xff0c;比如websocket&#xff08;程序生成的可执行…

springboot+vue志愿者在线报名服务管理系统java毕业设计源码+数据库

vuespringboot志愿服务管理系统 本项目是springbootvueElementuimysql源码 开发工具&#xff0c;idea和eclipse都可以,MySQL 源码下载地址 https://download.csdn.net/download/yibo2022/88401958?spm1003.2166.3001.6637.3https://download.csdn.net/download/yibo2022/884…

凯捷对汽车数字化的思考

标题凯捷&#xff08;中国&#xff09;对汽车行业数字化转型的探索 凯捷中国数字化研发团队有超过1200名专业顾问致力于数字化相关项目&#xff0c;分布在北京、天津、沈阳、呼和浩特、上海、昆山、杭州、广州、深圳等地&#xff0c;运用Rightshore交付模式和通过专业顾问为客…

Python 重要数据类型

目录 列表 序列操作 列表内置方法 列表推到式 字典 声明字典 字典基本操作 列表内置方法 字典进阶使用 字典生成式 附录 列表 在实际开发中&#xff0c;经常需要将一组&#xff08;不只一个&#xff09;数据存储起来&#xff0c;以便后边的代码使用。列表就是这样的…

流媒体方案之FFmepeg——实现物联网视频监控项目

目录 前言 一、FFmpeg介绍 二、FFmpeg简易理解 三、FFmpeg的重要概念 四、软硬件准备 五、移植、运行FFmpeg 六、运行FFmpeg 前言 最近想做一个安防相关的项目&#xff0c;所以跟着韦东山老师的视频来学习视频监控方案的相关知识&#xff0c;韦东山老师讲的课非常好&…

ABB YuMi协作式双臂机器人进入工厂,极大缓解劳动力短缺问题

原创 | 文 BFT机器人 日本SUS公司是一家为汽车和其他制造业提供铝框架和压铸铝部件的知名供应商&#xff0c;近年来&#xff0c;由于全球供应链面临严重中断&#xff0c;该公司希望能够寻找一家自动化供应商来帮助其恢复日本静冈县的产品生产。SUS公司表示&#xff0c;由于生产…

HarmonyOS——解决本地模拟器无法选择设备的问题

在使用deveco studio进行鸿蒙开发的时候&#xff0c;可能会遇到本地模拟器已经启动了&#xff0c;但是仍然无法选择本地模拟器中的设备&#xff0c;尤其在MAC环境中尤为常见。 解决办法&#xff1a; 先打开IDE启动本地模拟器&#xff0c;等模拟器启动后&#xff0c;退出IDE重新…

【代码】基于算术优化算法(AOA)优化参数的随机森林(RF)六分类机器学习预测算法/matlab代码

代码名称&#xff1a;基于算术优化算法&#xff08;AOA&#xff09;优化参数的随机森林&#xff08;RF&#xff09;六分类机器学习预测算法/matlab代码 使用算术优化算法&#xff08;AOA&#xff09;优化分类预测模型的参数&#xff0c;收敛性好&#xff0c;准确率提升明显&am…

Python 流程控制

目录 程序流程 顺序结构 分支结构 单分支 双分支 多分支 if 嵌套 循环结构 while循环 for 循环 退出循环 循环与分支嵌套 附录 程序流程 程序是由语句构成&#xff0c;而流程控制语句 是用来控制程序中每条语句执行顺序的语句。可以通过控制语句实现更丰富的逻辑…

后端项目操作数据库增删改查-使用MyBatis配置实现数据操作

一、创建一个数据表对应的实体类 在src/main/java/包名/路径下新建pojo.entity文件夹&#xff0c;如com.luoyang.small.pojo.entity&#xff0c;并在该文件夹下新增实体类java文件&#xff1a;如相册Album.java 该实体类的属性应与数据表的字段对应 数据表样例如下&#xff1a…

24年5月软考高项考哪些内容,考试大纲什么的?

信息系统项目管理师属于「计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试」中的高级资格考试。 也称「软考高项」&#xff0c;可以「以考代评」用来评副高级职称。 一、软考备考前期准备 信息系统项目管理师考试科目包括&#xff1a; 《综合知识》、《案例分…

html原生echart柱状图

html原生echart柱状图 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Bar Chart Example</title><!-- Include Chart.js library --><script src"https://cdn.jsdelivr.net/npm/…

Linux的基本指令(4)

目录 20.tar指令&#xff08;重要&#xff09;&#xff1a;打包/解包&#xff0c;不打开它&#xff0c;直接看内容 21.bc指令 22.uname –r指令&#xff1a; 23.重要的几个热键[Tab],[ctrl]-c, [ctrl]-d 20.tar指令&#xff08;重要&#xff09;&#xff1a;打包/解包&#…

手机上的记事本怎么打开?安卓手机通用的记事本APP

有不少上班族发现&#xff0c;自己想要在电脑上随手记录一些工作文字内容&#xff0c;直接使用电脑上的记事本工具来编辑文字是比较便捷的。但是如果想要在手机上记录文字内容&#xff0c;就找不到手机上的记事本了。那么手机上的记事本怎么打开&#xff1f;安卓手机通用的记事…