算法日记day 17(二叉树的最大、最小深度)

一、二叉树的最大深度

题目:

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:3

示例 2:

输入:root = [1,null,2]
输出:2

思路:

采用后序遍历的方法,一层一层的去判断子节点与父节点的距离,可以将一整个二叉树转变为一个个独立开来的二叉树,然后分别判断距离,在逐渐返回上一层,直到返回到根节点为止

代码:

public int maxDepth(TreeNode root) {// 如果根节点为空,即空树,深度为 0if (root == null) return 0;// 递归计算左子树的最大深度int leftDepth = maxDepth(root.left);// 递归计算右子树的最大深度int rightDepth = maxDepth(root.right);// 当前节点的深度为左右子树最大深度的较大值加上当前节点的深度 1int depth = Math.max(leftDepth, rightDepth) + 1;// 返回当前节点的深度return depth;
}
  • 首先进行判断,如果 root 为 null,即空树,则深度为 0。
  • 否则,分别递归计算左子树 root.left 和右子树 root.right 的最大深度。
  • 使用 Math.max 方法比较左右子树的最大深度,然后加上当前节点的深度 1,得到当前节点为根的子树的最大深度 depth
  • 最后返回计算得到的 depth 值作为结果。
  • maxDepth 方法通过递归调用自身,深度优先地计算每个节点的深度。
  • 如果树为空,则最大深度为 0。
  • 否则,通过递归分别计算左右子树的深度,并根据子树深度的比较确定当前子树的最大深度。
  • 返回的最终深度值代表整棵树的最大深度。

 此外代码还可以进行简化

public int maxDepth(TreeNode root) {if (root == null) {return 0;}return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}

二、二叉树的最小深度

题目:

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:

输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

思路:

代码与最大深度类似,但是有个误区,如果出现了左子树或者右子树一边为null的情况,最终结果就为1了,但是实际上这并不是从根节点到最近叶子节点的最短路径上的节点数量,因此需要额外的做出判断

代码:

public int minDepth(TreeNode root) {if (root == null) {return 0;}// 递归计算左子树的最小深度int leftDepth = minDepth(root.left);// 递归计算右子树的最小深度int rightDepth = minDepth(root.right);// 如果当前节点的左子树为空,右子树不为空,则最小深度为右子树的深度 + 1if (root.left == null && root.right != null) {return 1 + rightDepth;}// 如果当前节点的右子树为空,左子树不为空,则最小深度为左子树的深度 + 1if (root.left != null && root.right == null) {return 1 + leftDepth;}// 否则,当前节点的最小深度为左右子树最小深度的较小值 + 1return 1 + Math.min(leftDepth, rightDepth);
}
  1. 空树情况

    • 如果 root 为 null,即空树,则最小深度为 0,因此直接返回 0。
  2. 非空树情况

    • 首先递归计算左子树的最小深度 leftDepth
    • 然后递归计算右子树的最小深度 rightDepth
  3. 叶子节点情况

    • 如果当前节点 root 的左子树为空但右子树不为空,则最小深度为右子树的深度 + 1。这是因为要考虑到最小深度是从根节点到叶子节点的路径,所以只有右子树的情况需要特别处理。
    • 同理,如果当前节点的右子树为空但左子树不为空,则最小深度为左子树的深度 + 1。
  4. 一般情况

    • 如果当前节点既有左子树又有右子树,则最小深度为左右子树最小深度的较小值 + 1

 

三、完全二叉树节点的数量 

题目:

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

示例 1:

输入:root = [1,2,3,4,5,6]
输出:6

示例 2:

输入:root = []
输出:0

示例 3:

输入:root = [1]
输出:1

方法有很多

1、层序遍历

public int countNodes(TreeNode root) {if (root == null) {return 0;}// 递归计算左子树中节点的总数int leftNum = countNodes(root.left);// 递归计算右子树中节点的总数int rightNum = countNodes(root.right);// 当前节点(root)本身加上左右子树的节点数之和return 1 + leftNum + rightNum;
}

时间复杂度为O(n) 

2、利用完全二叉树的性质

思路:

由于完全二叉树不存在只有右子树而没有左子树的情况,因此我们可以通过判断左右子树最左边的节点和最右边节点的深度差来判断该二叉树中节点的数量,这样很大一部分中间的节点就没必要再次遍历,时间复杂度自然就小于O(n)了

代码:

public int countNodes(TreeNode root) {if (root == null) {return 0;}// 定义变量保存左子树和右子树TreeNode left = root.left;TreeNode right = root.right;int leftCount = 0, rightCount = 0;// 计算左子树的高度(即左子树的叶子节点数)while (left != null) {left = left.left;leftCount++;}// 计算右子树的高度(即右子树的叶子节点数)while (right != null) {right = right.right;rightCount++;}// 如果左子树的叶子节点数等于右子树的叶子节点数,则说明是满二叉树if (leftCount == rightCount) {// 计算满二叉树的节点总数并返回return (2 << leftCount) - 1;}// 如果不是满二叉树,则递归计算左右子树的节点总数,并加上当前节点int leftNum = countNodes(root.left);int rightNum = countNodes(root.right);return 1 + leftNum + rightNum;
}
  1. 空树情况

    • 如果 root 为 null,即空树,则节点总数为 0,直接返回 0。
  2. 非空树情况

    • 首先定义 left 和 right 变量分别指向根节点的左子树和右子树。
    • 使用 leftCount 和 rightCount 分别记录左子树和右子树的叶子节点数(即高度)。
    • 这里通过 while 循环找到左子树和右子树的最深的叶子节点,从而得到左右子树的高度。
  3. 判断满二叉树

    • 如果左子树的叶子节点数 leftCount 等于右子树的叶子节点数 rightCount,则说明当前子树是满二叉树。
    • 满二叉树的节点总数可以通过公式 (2 << leftCount) - 1 计算得到,即 2^leftCount - 1
  4. 非满二叉树情况

    • 如果左右子树的叶子节点数不相等,则该二叉树不是满二叉树。
    • 需要递归计算左右子树的节点总数,并将当前节点加上去(即加 1)。
  5. 递归调用

    • 如果不是满二叉树,则递归计算左子树和右子树的节点总数,分别存储在 leftNum 和 rightNum 中。
    • 最终返回的节点总数是当前节点 root 本身加上左右子树的节点总数。

3、迭代法 (BFS)

思路:

利用队列存储完全二叉树的所有节点,最后节点总数

代码:

public int countNodes(TreeNode root) {if (root == null) return 0; // 如果根节点为空,直接返回节点总数为0Queue<TreeNode> queue = new LinkedList<>(); // 创建一个队列用于BFSqueue.offer(root); // 将根节点加入队列int result = 0; // 初始化节点总数为0while (!queue.isEmpty()) { // 当队列不为空时循环int size = queue.size(); // 获取当前队列的大小,即当前层的节点数while (size-- > 0) { // 遍历当前层的所有节点TreeNode cur = queue.poll(); // 出队一个节点result++; // 节点总数加1,表示访问了一个节点// 将当前节点的左右子节点加入队列(如果存在)if (cur.left != null) queue.offer(cur.left);if (cur.right != null) queue.offer(cur.right);}}return result; // 返回节点总数
}
  1. 初始条件检查

    • 首先检查根节点 root 是否为空。若为空,则整棵树没有节点,直接返回节点总数为0。
  2. 队列初始化

    • 创建一个 Queue<TreeNode> 类型的队列 queue,使用 LinkedList 实现。
  3. BFS遍历

    • 将根节点 root 加入队列 queue
    • 初始化节点总数 result 为0,用于统计访问过的节点数。
  4. 主循环

    • 使用 while (!queue.isEmpty()) 进行 BFS 的迭代,直到队列为空。
    • 在每次迭代中,获取当前队列的大小 size,表示当前层的节点数。
  5. 处理当前层节点

    • 通过 size-- > 0 的循环方式遍历当前层的所有节点:
      • 从队列中取出一个节点 cur
      • 将 result 增加1,表示访问了一个节点。
  6. 扩展下一层

    • 检查当前节点 cur 的左右子节点是否存在,如果存在则加入队列 queue 中,以便在下一次迭代时处理。

 

四、平衡二叉树 

题目:

给定一个二叉树,判断它是否是 

平衡二叉树

示例 1:

输入:root = [3,9,20,null,null,15,7]
输出:true

示例 2:

输入:root = [1,2,2,3,3,null,null,4,4]
输出:false

示例 3:

输入:root = []
输出:true

思路:

是否平衡的前提是要判断左右子树的高度差是否平衡,采用后序遍历的方法,从叶子节点逐层向上排查左右子树高度差,若高度差大于1则不是平衡二叉树

代码:

递归计算每个节点的高度,并判断是否平衡

public int getHeight(TreeNode root) {if (root == null) {return 0; // 空节点的高度为0}int leftHeight = getHeight(root.left); // 获取左子树的高度int rightHeight = getHeight(root.right); // 获取右子树的高度// 如果左子树或右子树不是平衡的,则整棵树也不平衡,返回-1if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {return -1;}// 返回当前节点为根的子树的高度return Math.max(leftHeight, rightHeight) + 1;
}
  • 如果 root 为 null,则返回高度 0
  • 分别计算左子树和右子树的高度 leftHeight 和 rightHeight
  • 如果左子树或右子树的高度为 -1,或者左右子树的高度差大于 1,则返回 -1,表示当前子树不是平衡的。
  • 否则,返回当前节点为根的子树的高度,即 Math.max(leftHeight, rightHeight) + 1
//调用 getHeight(root) 方法,如果返回的高度不等于 -1,则说明是平衡二叉树;否则,不是平衡二叉树。
public boolean isBalanced(TreeNode root) {return getHeight(root) != -1;
}

这种方法的时间复杂度为 O(n),其中 n 是二叉树的节点数,因为每个节点都需要计算其高度一次。

今天的学习就到这里 

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

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

相关文章

STM32智能机器人控制系统教程

目录 引言环境准备智能机器人控制系统基础代码实现&#xff1a;实现智能机器人控制系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与导航系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;机器人控制与优化问题解决方案与优化收尾与总结 1. 引言 智能机器人控…

qt中charts图表的使用方法

折线图 #include "widget.h" #include "ui_widget.h" #include <QtCharts/QChart> #include <QtCharts/QChartView> #include <QtCharts/QLineSeries> #include<QVBoxLayout>Widget::Widget(QWidget *parent): QWidget(parent), …

Windows图形界面(GUI)-MFC-C/C++ - MFC项目工程框架解析

公开视频 -> 链接点击跳转公开课程博客首页 -> e​​​​​​链接点击跳转博客主页 目录 MFC项目 项目选择 配置安装 程序引导 MFC框架 环境设置 程序框架 代码编写 MFC解析 程序入口 执行流程 代码结构 应用程序类 窗口框架类 消息处理 消息类型 消息…

ML.Net 学习之使用经过训练的模型进行预测

什么是ML.Net&#xff1a;&#xff08;学习文档上摘的一段&#xff1a;ML.NET 文档 - 教程和 API 参考 | Microsoft Learn 【学习入口】&#xff09; 它使你能够在联机或脱机场景中将机器学习添加到 .NET 应用程序中。 借助此功能&#xff0c;可以使用应用程序的可用数据进行自…

一个简单好用安全的开源交互审计系统,支持SSH,Telnet,Kubernetes协议(带私活)

前言 在当今的企业网络环境中&#xff0c;远程访问和交互审计成为了保障网络安-全的重要组成部分。然而&#xff0c;现有的解-决方案往往存在一些痛点&#xff0c;如复杂的配置、有限的协议支持、以及审计功能的不足。这些问题不仅增加了IT管理员的负担&#xff0c;也为企业的…

基于R语言复杂数据回归与混合效应模型【多水平/分层/嵌套】技术与代码

回归分析是科学研究特别是生态学领域科学研究和数据分析十分重要的统计工具&#xff0c;可以回答众多科学问题&#xff0c;如环境因素对物种、种群、群落及生态系统或气候变化的影响&#xff1b;物种属性和系统发育对物种分布&#xff08;多度&#xff09;的影响等。纵观涉及数…

HarmonyOS NEXT零基础入门到实战-第四部分

自定义组件: 概念: 由框架直接提供的称为 系统组件&#xff0c; 由开发者定义的称为 自定义组件。 源代码&#xff1a; Component struct MyCom { build() { Column() { Text(我是一个自定义组件) } } } Component struct MyHeader { build() { Row(…

路由器ip地址脱机是什么意思?怎么应对

在数字化时代&#xff0c;路由器作为家庭或企业网络连接的核心设备&#xff0c;其稳定性和连通性对于我们的网络体验至关重要。然而&#xff0c;有时我们可能会遇到路由器IP地址显示脱机的情况&#xff0c;这不仅影响了我们的网络访问&#xff0c;还可能对工作和娱乐造成不便。…

【C语言】 约瑟夫环,循环链表实现

1、循环链表实现约瑟夫环&#xff0c;每次经过特定步数删除一个元素 //looplist.h #ifndef LOOPLIST_H #define LOOPLIST_H #include<stdio.h> #include<string.h> #include<stdlib.h>typedef int datatype;typedef struct Node {union {int len;datatype d…

Elasticsearch:Java ECS 日志记录 - log4j2

ECS 记录器是你最喜欢的日志库的格式化程序/编码器插件。它们可让你轻松将日志格式化为与 ECS 兼容的 JSON。ECS 兼容的 JSON 日志记录可以帮我们简化很多分析&#xff0c;可视化及解析的工作。在今天的文章里&#xff0c;我来详述如何在 Java 应用里生成 ECS 相兼容的日志。 …

tensorflow keras Model.fit returning: ValueError: Unrecognized data type

题意&#xff1a;TensorFlow Keras 的 Model.fit 方法返回了一个 ValueError&#xff0c;提示数据类型无法识别 问题背景&#xff1a; Im trying to train a keras model with 2 inputs: an image part thats a tf.data.Dataset and a nor mal part represented by a pd.DataF…

【中项】系统集成项目管理工程师-第4章 信息系统架构-4.5技术架构

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

数据结构之判断平衡二叉树详解与示例(C,C++)

文章目录 AVL树定义节点定义计算高度获取平衡因子判断是否为平衡二叉树完整示例代码结论 在计算机科学中&#xff0c;二叉树是一种非常重要的数据结构。它们被广泛用于多种算法中&#xff0c;如排序、查找等。然而&#xff0c;普通的二叉树在极端情况下可能退化成链表&#xff…

C#基于SkiaSharp实现印章管理(4)

前几篇文章实现了绘制不同外形印章的功能&#xff0c;印章内部一般包含圆形、线条等形状&#xff0c;有些印章内部还有五角星&#xff0c;然后就是各种样式的文字。本文实现在印章内部绘制圆形、线条、矩形、椭圆等四种形状。   定义FigureType枚举记录印章内部形状&#xff…

pcie数据传输

一 数据传输通道总体设计 在上传数据时首先将 FPGA 中数据缓存到 DDR3 存储器&#xff0c;然后上位机请求后把数据从DDR3 存储器中取出并通过 PCIE 总线将数据传输到上位机&#xff1b;在下传数据时上位机中的数据首先通过 PCIE 总线下传至 FPGA&#xff0c;FPGA 读取这些数据并…

小程序内嵌uniapp页面跳转回小程序指定页面方式

使用微信小程序提供的Api&#xff1a;wx.miniProgram.navigateTo 在小程序中嵌套uniapp的H5页面&#xff0c;并使用wx.miniProgram.navigateTo进行页面跳转&#xff0c;需要确保满足以下条件&#xff1a; 你的小程序必须是通过uniapp构建的&#xff0c;并且支持小程序嵌套。 你…

系统架构设计师教程 第3章 信息系统基础知识-3.8 典型信息系统架构模型-解读

系统架构设计师教程 第3章 信息系统基础知识-3.8 典型信息系统架构模型-解读 3.8.1 政府信息化与电子政务3.8.1.1 电子政务的概念3.8.1.2 电子政务的内容3.8.1.2.1 政府与政府3.8.1.2.2 政府对企/事业单位3.8.1.2.3 政府对居民3.8.1.2.4 企业对政府3.8.1.2.5 居民对政府 3.8.1…

【HarmonyOS】HarmonyOS NEXT学习日记:六、渲染控制、样式结构重用

【HarmonyOS】HarmonyOS NEXT学习日记&#xff1a;六、渲染控制、样式&结构重用 渲染控制包含了条件渲染和循环渲染&#xff0c;所谓条件渲染&#xff0c;即更具状态不同&#xff0c;选择性的渲染不同的组件。 而循环渲染则是用于列表之内的、多个重复元素组成的结构中。 …

RabbitMQ的学习和模拟实现|GTest测试框架的介绍和简单使用

GTest 项目仓库&#xff1a;https://github.com/ffengc/HareMQ GTest GTest是什么我们需要学习的GTest功能宏断言事件机制 全局测试套件独立测试套件 GTest是什么 GTest是一个跨平台的 C单元测试框架&#xff0c;由google公司发布。gtest是为了在不同平台上为编写C单元测…

JAVA JUC学习笔记

基础知识 1、进程和线程的对比 进程基本上相互独立的&#xff0c;而线程存在于进程内&#xff0c;是进程的一个子集进程拥有共享的资源&#xff0c;如内存空间等&#xff0c;供其内部的线程共享进程间通信较为复杂 同一台计算机的进程通信称为 IPC&#xff08;Inter-process …