【代码随想录训练营】【Day16】第六章|二叉树|104.二叉树的最大深度|559.n叉树的最大深度|111.二叉树的最小深度|222.完全二叉树的节点个数
二叉树的最大深度
题目详细:LeetCode.104
递归法很容易理解:
- 定义一个全局变量max, 记录二叉树的最大深度
- 在递归函数中增加一个深度参数,表示当前的节点的深度
- 然后对二叉树进行深度优先遍历
- 当遍历到叶子节点时,比较当前节点的深度和记录的最大深度,保持最大值
- 当树遍历完成后,返回记录的最大深度即可
Java解法(递归,深度优先遍历):
class Solution {private int max = 0;public int maxDepth(TreeNode root) {this.dfs(root, 0);return this.max;}public void dfs(TreeNode root, int deep){if(null == root){this.max = deep > this.max ? deep : this.max;return;}this.dfs(root.left, deep + 1);this.dfs(root.right, deep + 1);}
}
递归法很容易掌握,所以我想尝试用迭代法来解题,但使用前序遍历迭代法来解题好像不是很方便;回到观察问题本身,我发现求二叉树的最大深度,其实就是求叶子节点的最大层数,那么我们也可以利用层序遍历(广度优先遍历)来解题:
Java解法(层序遍历,迭代法,广度优先遍历):
class Solution {public int maxDepth(TreeNode root) {return this.bfs(root);}public int bfs(TreeNode root){Queue<TreeNode> queue = new LinkedList<>();if(null != root) queue.offer(root);int deep = 0;while(!queue.isEmpty()){deep++;int len = queue.size();while(len-- > 0){TreeNode node = queue.poll();if(null != node.left) queue.offer(node.left);if(null != node.right) queue.offer(node.right);}}return deep;}
}
n叉树的最大深度
题目详细:LeetCode.559
这道题和上一题的二叉树的最大深度有异曲同工之妙,区别在于:
- n叉树的多个节点,使用的是指针数组来存储
- 除了根节点可能为空外,在遍历孩子节点过程中,不会遍历到空节点
- 叶子节点的定义有两种情况:
- 孩子节点数组为空(即 node.children == null ,这种情况在样本数据中未出现)
- 孩子节点数组长度为 0
所以这道题利用递归法来解决非常简单,跟求解二叉树的最大深度的过程类似,只是这次改为对每一个孩子节点都进行深度优先遍历,最后保留深度最大值。
Java解法(递归,深度优先遍历):
class Solution {public int maxDepth(Node root) {return this.dfs(root);}public int dfs(Node root){int deep = 0;if(null == root) return deep;for(Node node: root.children){deep = Math.max(deep, this.dfs(node));}return deep + 1;}
}
二叉树的最小深度
题目详细:LeetCode.111
这道题与上面找二叉树的最大深度刚好相反,要求找二叉树的最小深度,但是其解题思路是相似的:
- 同样是遍历到树的叶子节点,只不过一个是记录树的最大深度,一个是记录树的最小深度罢了
- 这道题的难点在于如何确定是否到达了叶子节点
- 因为求二叉树的最大深度时,我们并不需要去关心当前节点是否是叶子节点
- 我们只需要注意当遍历到空节点时进行回溯,即空节点的深度 - 1,同时与记录的深度进行比较,保持一个最大值即可
- 但是在求二叉树的最小深度时,就不一样了,因为在遍历到空节点时,会出现这四种情况,都有着各自的处理方式:
- 当前节点的左节点为空,但其右节点不为空,非叶子节点,继续遍历右子树查找叶子节点
- 当前节点的左节点不为空,但其右节点为空,非叶子节点,继续遍历右子树查找叶子节点
- 当前节点的左右节点都不为空 ,继续遍历左右子树查找叶子节点
- 当前节点的左右节点都为空,属于叶子节点,比较当前节点的深度并记录最小深度
- 因为求二叉树的最大深度时,我们并不需要去关心当前节点是否是叶子节点
- 可见,在求二叉树的最小深度的过程中,并不涉及回溯,因为如果遍历到空节点就回溯的话,其回溯到的节点不一定是叶子节点
- 在求解过程中,只有必须判断当前节点是否是叶子节点,才能够更新记录值。
Java解法(递归,深度优先遍历,模拟思路版):
class Solution {private int min = Integer.MAX_VALUE;public int minDepth(TreeNode root) {if(null != root){this.dfs(root, 1);return min;}return 0;}public void dfs(TreeNode root, int deep){if(null != root && null == root.left && null == root.right){min = Math.min(min, deep);return;}if(null != root.left) this.dfs(root.left, deep + 1);if(null != root.right) this.dfs(root.right, deep + 1);}
}
Java解法(递归,深度优先遍历,精简版):
class Solution {public int minDepth(TreeNode root) {return dfs(root);}public int dfs(TreeNode root){if(null == root) return 0;if(null != root.left && null == root.right)return 1 + dfs(root.left);if(null == root.left && null != root.right)return 1 + dfs(root.right);return 1 + Math.min(dfs(root.left), dfs(root.right));}
}
虽然递归法写起来很简单方便,但是经过测试发现,利用递归来解这道题,虽然能够AC,但是速度并不快,为什么呢?
- 因为递归法的算法思想,是深度优先遍历
- 在二叉树中,它需要去对左右子树都进行深度优先遍历,得到各自的最小深度,然后再比较两者选取一个最小值
- 假如二叉树的左子树深度很小,但是右子树的深度很大
- 那么我们本来只需要通过左子树就可以确定最小深度,却还需要去等待右子树的递归结果,才可以得到最终的结果
- 那毫无疑问,递归右子树是在做无用功的
那么也就是说,我们可以按从上到下,从左到右
的顺序来遍历树,假设我们优先在左子树就遍历到了叶子节点得到其深度,那么后面的节点我们都可以不用去关心了,其叶子节点的深度就是二叉树的最小深度,所以优化这道题的关键就在于遍历方式,所以我们可以利用层序遍历来优化这道题:
Java解法(迭代法,层序遍历,广度优先遍历):
class Solution {public int minDepth(TreeNode root) {if(root == null) return 0;return bfs(root);}public int bfs(TreeNode root){Queue<TreeNode> queue = new LinkedList<>();if(null != root) queue.offer(root);int deep = 1;while(!queue.isEmpty()){int n = queue.size();while(n-- > 0){root = queue.poll();if(null == root.left && null == root.right) return deep;if(null != root.left) queue.offer(root.left);if(null != root.right) queue.offer(root.right);}deep++;}return deep;}
}
完全二叉树的节点个数
题目详细:LeetCode.222
这道题如果不涉及完全二叉树,那么我们用任何一种遍历方式来统计二叉树中的节点个数都是可以的,只需要一遍遍历,一边个数 + 1就行了,那么我们可以得到非常大智若愚的递归解法:
Java解法(递归,深度优先遍历,前序遍历):
class Solution {public int countNodes(TreeNode root) {if(null == root) return 0;return 1 + countNodes(root.left) + countNodes(root.right);}
}
那么这道题又何必是求完全二叉树的节点个数呢,为什么不直接让我求二叉树的节点个数就得了?此时,我注意到题目最下面一段小字:
进阶:遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?
确实,我们如果使用遍历树的方法来统计节点,得到的都是时间复杂度为 O(n) 的算法,完全没有利用到样本数据是一棵完全二叉树的特点,关于完全二叉树的概念和特点详细可以查阅:《代码随想录》— 完全二叉树
在了解了完全二叉树的特点之后,我们不难发现,我们可以利用层序遍历
:
- 当遍历到当前节点的某一子节点为空时,那么我们就可以确定其空子节点之前的节点都是非空的
- 那么只需要
累计之前遍历过的节点数量 + 与空子节点同一层的之前的节点长度
,就可以得到该完全二叉树的节点个数了
Java解法(迭代法,广度优先遍历,层序遍历):
class Solution {public int countNodes(TreeNode root) {return this.bfs(root);}public int bfs(TreeNode root){Queue<TreeNode> queue = new LinkedList<>();if(null != root) queue.offer(root);int sum = 0;while(!queue.isEmpty()){int n = queue.size();while(n-- > 0){sum++;root = queue.poll();if(null != root.left) queue.offer(root.left);if(null != root.right) queue.offer(root.right);if(null == root.left || null == root.right){return sum + queue.size();}}}return sum;}
}
前两天对二叉树的题我都做得很详细,所以基础算是牢固,而且通过昨天的联系,也明白了二叉树的题目无非就是两个要点:选择最合适的遍历方法 + 处理节点的逻辑方法,在今天的练习过后,我更加肯定了这一观点,并且对二叉树不同的遍历方法更加重视了。
题目看似不停的变,其实万变不离其宗,只要遍历方法选对了,剩下的只需要根据题目需求来处理目标节点就可以解题了,对二叉树的遍历越理解,以及不同类型二叉树各自的特点越熟悉,解起二叉树的题来简直就是得心应手,令我感叹道:
读书破万卷,下笔如有神。
相关文章:
【代码随想录训练营】【Day16】第六章|二叉树|104.二叉树的最大深度|559.n叉树的最大深度|111.二叉树的最小深度|222.完全二叉树的节点个数
二叉树的最大深度 题目详细:LeetCode.104 递归法很容易理解: 定义一个全局变量max, 记录二叉树的最大深度在递归函数中增加一个深度参数,表示当前的节点的深度然后对二叉树进行深度优先遍历当遍历到叶子节点时,比较…...

transformer总结
1.注意力机制 意义:人类的注意力机制极大提高了信息处理的效率和准确性。 公式: 1)自注意力机制 b都是在考虑了所有a的情况下生成的。 以产生b1向量为例: 1.在a这个序列中,找到与a1相关的其他向量 2.每个向量与a1关联的程度&a…...
dart flutter入门教程,开发手册 分享
我最近在学校dart flutter.这是我收集的一些手册和教程. 不需要关注公众号,不需要加好友. 我发现flutter(dart)的中文资料比较奇缺.入门的教程非常多.但是api手册几乎没有(全是英文的). 收集原则 1.中文(我英文不好) 2.不要pdf的,网上有一些pdf的 从入门到进阶的,但是太长…...

教育舆情监测关键词有哪些,TOOM教育舆情监测系统流程?
教育舆情监测是指对教育领域的舆情进行收集、分析和处理的过程。舆情是指公众在各种渠道上对教育政策、教育机构、教育事件等方面的言论、态度和情绪。通过对教育舆情的监测和分析,可以了解公众对教育行业的看法和反应,提高对教育行业的管控能力…...

MySQL高级(一)
MySQL-day01 1 MySQL简介 1.1 MySQL简介 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB(创始人Michael Widenius)公司开发,2008被Sun收购(10亿美金),2009年Sun被Oracle收购。MariaDBMaria…...

如何将Python项目部署到新电脑上运行?
如何将Python项目部署到新电脑上运行? 在工作中,可能需要在新服务器上部署项目代码,例如新增服务器、把测试环境的代码部署到生产环境等。 在生活中,也会遇到换新电脑,需要将自己在旧电脑上写的(项目&…...

JVM和JAVA体系结构
1、为什么要学习JVM作为Java工程师的你曾被伤害过吗?你是否也遇到过这些问题?运行着的线上系统突然卡死,系统无法访问,甚至直接OOM想解决线上JVM GC问题,但却无从下手新项目上线,对各种JVM参数设置一脸茫然…...

(十)、通过云对象修改阅读量+点赞功能的实现【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】
1,通过云对象importObj修改阅读量 1.1 新建云对象 1.2 云对象中写自增自减方法 封装云对象utilsObj中的自增自减方法,方法名取为operation,传递4个参数。 // 云对象教程: https://uniapp.dcloud.net.cn/uniCloud/cloud-obj // jsdoc语法提…...
刷力扣的第一天脑子要长出来的感觉(怎么有人大四才开始啊啊啊啊啊啊啊啊啊啊啊啊,又是等成绩的一天,)
刷力扣的第一天脑子要长出来的感觉(为什么大四才开始啊啊啊啊啊啊啊啊啊啊啊啊) emmm,自己还是想不太出来(只是一点想法),可能还是会参考评论区,求各位轻喷 分析:带符号一定不是回…...

Nuclei文*件上*传FUZZ POC
目录 1.前言 2. Nuclei文件上传FUZZ POC 3. 实战中的应用 1.前言 该文件上传FUZZ POC主要来源于一个靶*场,该POC 主要用来FUZZ目标js页面中的upload ajax请求,以此来进一步尝试文件上传漏*洞利*用。 这里也要感谢下“打工仔1号”提供的开*发人员常见的文*件上*传javaScr…...
完美解决方案-雪花算法ID到前端之后精度丢失问题
最近公司的一个项目组要把以前的单体应用进行为服务拆分,表的ID主键使用Mybatis plus默认 的雪花算法来生成。 快下班的时候,小伙伴跑过来找我,:“快给我看看这问题,卡这卡了小半天了!”。连拉带拽&#x…...
工程管理系统源码之高效的工程项目管理软件
高效的工程项目管理软件不仅能够提高效率还应可以帮你节省成本提升利润 在工程行业中,管理不畅以及不良的项目执行,往往会导致项目延期、成本上升、回款拖后,最终导致项目整体盈利下降。企企管理云业财一体化的项目管理系统,确保…...
390. 消除游戏
列表 arr 由在范围 [1, n] 中的所有整数组成,并按严格递增排序。请你对 arr 应用下述算法:从左到右,删除第一个数字,然后每隔一个数字删除一个,直到到达列表末尾。重复上面的步骤,但这次是从右到左。也就是…...
springBoot JPA代码生成器
介绍通过IDEA配置文件,根据数据库表结构快速生产Service、ServiceImpl、repository、repositoryImpl、自动生成常用的jpa增删改查等方法。使用的版本Spring Boot2.1.6.RELEASE spring-boot-starter-data-jpa使用idea 生成代码步骤打开idea(https://images.gitee.co…...

相同月利率条件下不同还款方式贷款的APR与IRR研究
文章目录前提假设一次性还本付息先息后本等额本息等额本金简单二分法求解IRR的程序汇总实验对比前提假设 因为常见的信贷产品还款期数定义都是按照月,假设只借一期的利率(月利率)为r,在此条件下,研究不同还款方式下的…...

【论文】智能隧道检测车的现状及改进策略
本文转载自《智慧城轨》2022年第11期 作者:黄丹樱1,韦强1,朱椰毅2,范骁1,林浩立1 单位:1 浙江师范大学工学院;2 浙江金温铁道开发有限公司 声明:本文仅用于学术分享,不做商业用途,如有侵权,联…...
【代码随想录二刷】Day16-二叉树-C++
代码随想录二刷Day16 每日任务 104.二叉树的最大深度 559.n叉树的最大深度 111.二叉树的最小深度 222.完全二叉树的节点个数 语言:C 104. 二叉树的最大深度 链接:https://leetcode.cn/problems/maximum-depth-of-binary-tree/ 递归法(前序…...

Lecture5 实现线性回归(Linear Regression with PyTorch)
目录 1 Pytorch实现线性回归 1.1 实现思路 1.2 完整代码 2 各部分代码逐行详解 2.1 准备数据集 2.2 设计模型 2.2.1 代码 2.2.2 代码逐行详解 2.2.3 疑难点解答 2.3 构建损失函数和优化器 2.4 训练周期 2.5 测试结果 3 线性回归中常用优化器 1 Pytorch实现线性回归…...
Python与Matlab svd分解的差异
1.差异说明 Matlab和Python的NumPy库中的SVD函数(np.linalg.svd)都是用来对矩阵进行奇异值分解(SVD)的函数,但它们在默认参数和返回结果方面有一些差异。 在Matlab中,SVD函数的默认行为是计算矩阵的完整SVD,即对于一…...
2023年光模块行业发展趋势及未来前景
随着数字化时代的到来,互联网行业的快速发展,网络通信设备行业的发展也在逐渐加速。光模块作为网络设备的重要组成部分,也在不断创新和发展。那么,光模块行业的未来发展趋势又是怎样的呢?接下来就跟着易天光通信&#…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...

PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
MySQL用户和授权
开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务: test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...
大数据学习(132)-HIve数据分析
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言Ǵ…...

【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...