【代码随想录训练营】【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年光模块行业发展趋势及未来前景
随着数字化时代的到来,互联网行业的快速发展,网络通信设备行业的发展也在逐渐加速。光模块作为网络设备的重要组成部分,也在不断创新和发展。那么,光模块行业的未来发展趋势又是怎样的呢?接下来就跟着易天光通信&#…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践
在电商行业蓬勃发展的当下,多平台运营已成为众多商家的必然选择。然而,不同电商平台在商品数据接口方面存在差异,导致商家在跨平台运营时面临诸多挑战,如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...
aurora与pcie的数据高速传输
设备:zynq7100; 开发环境:window; vivado版本:2021.1; 引言 之前在前面两章已经介绍了aurora读写DDR,xdma读写ddr实验。这次我们做一个大工程,pc通过pcie传输给fpga,fpga再通过aur…...
篇章一 论坛系统——前置知识
目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …...
设计模式域——软件设计模式全集
摘要 软件设计模式是软件工程领域中经过验证的、可复用的解决方案,旨在解决常见的软件设计问题。它们是软件开发经验的总结,能够帮助开发人员在设计阶段快速找到合适的解决方案,提高代码的可维护性、可扩展性和可复用性。设计模式主要分为三…...
可视化图解算法48:有效括号序列
牛客网 面试笔试 TOP101 | LeetCode 20. 有效的括号 1. 题目 描述 给出一个仅包含字符(,),{,},[和],的字符串,判断给出的字符串是否是合法的括号序列 括号必须以正确的顺序关闭,"()"和"()[]{}"都是合法的括号序列&…...
Linux知识回顾总结----进程状态
本章将会介绍进程的一些概念:冯诺伊曼体系结构、进程是什么,怎么用、怎么表现得、进程空间地址、物理地址、虚拟地址、为什么存在进程空间地址、如何感性得去理解进程空间地址、环境变量是如何使用的。 目录 1. 冯诺伊曼体系结构 1.1 是什么 1.2 结论 …...
01-VMware16虚拟机详细安装
官网地址:https://www.vmware.com/cn.html 1.1 打开下载好的 .exe 文件, 双击安装。 1.2 点击下一步 1.3 先勾选我接受许可协议中的条款,然后点击下一步 1.4 自定义安装路径,注意这里的文件路径尽量不要包含中文,完成…...
【Unity】R3 CSharp 响应式编程 - 使用篇(二)
一、通用的事件监听用法 using System;using R3;using UnityEngine;namespace Aladdin.Standard.Observable.Common{public class CommonObservable : MonoBehaviour{// 默认会调用1次public SerializableReactiveProperty<int> serializableReactiveProperty;…...
系统模块与功能设计框架
系统模块与功能设计框架,严格遵循专业架构设计原则,基于行业标准(如微服务架构、DDD领域驱动设计)构建。设计采用分层解耦模式,确保可扩展性和可维护性,适用于电商、企业服务、数字平台等中大型系统。 系统…...
