LeetCode 110.平衡二叉树(Java/C/Python3/Go实现含注释说明,Easy)

标签

  • 深度优先搜索
  • 递归

题目描述

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡的二叉树定义为:

一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。

原题:LeetCode 110.平衡二叉树

思路及实现

方法一:自顶向下递归(纯递归)

思路

定义函数 height\texttt{height}height,用于计算二叉树中的任意一个节点 ppp 的高度:
在这里插入图片描述
为了判断二叉树是否平衡,我们可以采用一个自顶向下的递归方法。该方法通过计算每个节点左右子树的高度差,并与 1 进行比较来判断当前子树是否平衡。如果当前子树平衡,则继续递归检查其子节点。

代码实现
Java版本
class Solution {  // 判断二叉树是否平衡  public boolean isBalanced(TreeNode root) {  // 如果根节点为空(即树为空),则树是平衡的  if (root == null) {  return true;  }  // 否则,判断当前节点的左右子树高度差是否不超过1,并且左右子树都是平衡的  else {  return Math.abs(height(root.left) - height(root.right)) <= 1 &&   isBalanced(root.left) && // 递归判断左子树是否平衡  isBalanced(root.right);  // 递归判断右子树是否平衡  }  }  // 计算树的高度  public int height(TreeNode root) {  // 如果根节点为空(即树为空或到达叶子节点的下一层),则返回高度为0  if (root == null) {  return 0;  }  // 否则,返回当前节点左子树和右子树中的较大高度加1(当前节点的高度为其子树的最大高度加1)  else {  return Math.max(height(root.left), height(root.right)) + 1;  }  }  // TreeNode类(假设已经在外部定义)  // class TreeNode {  //     int Val;  //     TreeNode Left;  //     TreeNode Right;  //     TreeNode(int val) { Val = val; }  // }  }

说明:isBalanced 方法检查树是否平衡,同时递归地计算左右子树的高度。height 方法返回树的高度。

C语言版本
int height(struct TreeNode* root) {if (root == NULL) {return 0;} else {return fmax(height(root->left), height(root->right)) + 1;}
}bool isBalanced(struct TreeNode* root) {if (root == NULL) {return true;} else {return fabs(height(root->left) - height(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);}
}

说明:在C语言中,我们使用了fmax函数来计算两个整数中的较大值,并且fabs函数用于计算绝对值。

Python3版本
class Solution:def isBalanced(self, root: TreeNode) -> bool:def height(root: TreeNode) -> int:if not root:return 0return max(height(root.left), height(root.right)) + 1if not root:return Truereturn abs(height(root.left) - height(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right)

说明:在Python中,我们约定如果子树不平衡,则height函数返回-1,这样可以在isBalanced中直接利用返回值进行判断。

Golang版本
package mainimport ("math"
)func isBalanced(root *TreeNode) bool {if root == nil {return true}return abs(height(root.Left) - height(root.Right)) <= 1 && isBalanced(root.Left) && isBalanced(root.Right)
}func height(root *TreeNode) int {if root == nil {return 0}return max(height(root.Left), height(root.Right)) + 1
}func max(x, y int) int {if x > y {return x}return y
}func abs(x int) int {if x < 0 {return -1 * x}return x
}作者:力扣官方题解
链接:https://leetcode.cn/problems/balanced-binary-tree/solutions/377216/ping-heng-er-cha-shu-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

说明:在Golang版本中,我们使用了一个辅助函数dfs来进行深度优先搜索,该函数返回子树的高度和是否平衡两个值。如果子树不平衡,则dfs返回-1和false。absmax是辅助函数,分别用于计算绝对值和取两个整数中的较大值。

复杂度分析

  • 时间复杂度
    时间复杂度为 O(n),其中 n 是二叉树中的节点数。这是因为在递归的过程中,我们需要访问每一个节点来计算其左右子树的高度,并且对每个节点都要执行一次判断是否平衡的操作(比较高度差以及递归检查子树是否平衡)。每个节点最多被访问一次,因此总的时间复杂度是线性的。

  • 空间复杂度
    空间复杂度取决于递归调用的深度,也就是树的深度。在最坏的情况下,当树完全不平衡时(例如每个节点都只有左子节点或右子节点),递归的深度会达到树的高度,也就是 O(n)。此时,递归调用栈需要存储 O(n) 个节点信息。

然而,在平均情况下,二叉树是平衡的,其深度通常是对数级别的,即 O(log n)。因此,在平均情况下,空间复杂度是 O(log n)。

但需要注意的是,空间复杂度并不只包括递归调用栈的开销,还包括系统为函数调用分配的其他资源(如局部变量等)。但在判断二叉树是否平衡的问题中,这些开销通常相对较小,可以忽略不计。

  • 总结
    时间复杂度:O(n)
    空间复杂度(最坏情况):O(n)
    空间复杂度(平均情况):O(log n)
    其中,n 是二叉树中的节点数。

方法一:自顶向下递归(带后序遍历)

思路

方法一由于是自顶向下递归,因此对于同一个节点,函数 height 会被重复调用,导致时间复杂度较高。如果使用自底向上的做法,则对于每个节点,函数 height 只会被调用一次。

自底向上递归的做法类似于后序遍历,对于当前遍历到的节点,先递归地判断其左右子树是否平衡,再判断以当前节点为根的子树是否平衡。如果一棵子树是平衡的,则返回其高度(高度一定是非负整数),否则返回 −1-1−1。如果存在一棵子树不平衡,则整个二叉树一定不平衡。

方式二:带后序遍历的递归方法(自底向上)

思路

带后序遍历的递归方法(自底向上)在遍历到每个节点时,首先递归地检查其左右子树是否平衡,并返回子树的高度。如果子树不平衡(即高度差大于1),则立即返回-1表示不平衡,并向上传递这个信息。如果子树平衡,则返回其高度,继续向上传递。这样,在遍历到根节点时,就可以知道整棵树是否平衡。

代码实现

Java版本
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class Solution {public boolean isBalanced(TreeNode root) {return height(root) != -1;}private int height(TreeNode node) {if (node == null) {return 0;}int leftHeight = height(node.left);if (leftHeight == -1) {return -1;}int rightHeight = height(node.right);if (rightHeight == -1) {return -1;}if (Math.abs(leftHeight - rightHeight) > 1) {return -1;}return Math.max(leftHeight, rightHeight) + 1;}
}

说明:在Java版本中,isBalanced方法调用height方法来判断树是否平衡。height方法递归地计算每个节点的高度,并在发现不平衡时返回-1。

C语言版本
#include <limits.h>typedef struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
} TreeNode;int height(TreeNode* node) {if (node == NULL) {return 0;}int leftHeight = height(node->left);if (leftHeight == -1) {return -1;}int rightHeight = height(node->right);if (rightHeight == -1) {return -1;}if (abs(leftHeight - rightHeight) > 1) {return -1;}return MAX(leftHeight, rightHeight) + 1;
}bool isBalanced(TreeNode* root) {return height(root) != -1;
}

说明:在C语言版本中,同样使用height函数来计算节点高度并判断平衡性。注意这里使用了limits.h中的INT_MIN来表示-1的整数类型(但在这个例子中我们直接返回-1),以及自定义的MAX宏来获取两个数中的较大值(或者可以使用#include <stdlib.h>中的max函数,如果存在的话)。

Python3版本
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef isBalanced(root):def height(node):if not node:return 0leftHeight = height(node.left)if leftHeight == -1:return -1rightHeight = height(node.right)if rightHeight == -1:return -1if abs(leftHeight - rightHeight) > 1:return -1return max(leftHeight, rightHeight) + 1return height(root) != -1

说明:在Python3版本中,我们定义了一个嵌套函数height来计算节点高度,并在isBalanced函数中调用它。Python中没有类型定义,所以我们直接使用类定义来创建树节点。

Golang版本
package main  import (  "fmt"  "math"  
)  type TreeNode struct {  Val   int  Left  *TreeNode  Right *TreeNode  
}  func isBalanced(root *TreeNode) bool {  return height(root) != -1  
}  func height(node *TreeNode) int {  if node == nil {  return 0  }  leftHeight := height(node.Left)  if leftHeight == -1 {  return -1  }  rightHeight := height(node.Right)  if rightHeight == -1 {  return -1  }  if math.Abs(float64(leftHeight-rightHeight)) > 1 {  return -1  }  return int(math.Max(float64(leftHeight), float64(rightHeight))) + 1  
}  

复杂度分析

  • 时间复杂度:O(n),其中n是二叉树中的节点数。每个节点最多被访问一次,因此总的时间复杂度是线性的。
  • 空间复杂度:O(h),其中h是二叉树的高度。这是由递归调用栈的深度决定的。在最坏的情况下(树完全不平衡),空间复杂度为O(n)。然而,在平均情况下,二叉树是平衡的,其高度通常是对数级别的,即O(log n)。但需要注意的是,这里的空间复杂度不包括可能由操作系统分配的系统

总结

针对上面提到的自顶向下递归(方式一)和自底向上递归(方式二)的二叉树平衡性检查方法,我们可以进行如下总结:

方式优点缺点时间复杂度空间复杂度
方式一(自顶向下递归)直观易理解,直接根据定义判断可能产生大量重复计算,效率较低O(n)O(h)(h为树的高度,最坏情况下为O(n))
方式二(自底向上递归)利用后序遍历减少重复计算,效率高依赖于递归和高度差的比较,可能难以理解O(n)O(h)(h为树的高度,最坏情况下为O(n))

注意:在方式二中,虽然空间复杂度在最坏情况下为O(n),但这是因为递归调用栈的深度可能达到n。在平均情况下,对于平衡树,空间复杂度为O(log n)。

相似题目

以下是一些与判断二叉树平衡性相关的相似题目,它们涉及树的遍历、深度或高度的计算等概念:

相似题目难度链接
LeetCode 104 二叉树的最大深度简单LeetCode-104
LeetCode 110 平衡二叉树简单LeetCode-110
LeetCode 111 二叉树的最小深度简单LeetCode-111
LeetCode 543 二叉树的直径简单LeetCode-543
LeetCode 124 二叉树中的最大路径和困难LeetCode-124

这些题目都涉及到对二叉树的遍历和深度/高度的计算,可以通过递归或迭代的方式解决。其中,LeetCode 110题目与本文讨论的二叉树平衡性检查最为相似。

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

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

相关文章

MFC列表控件用ADO添加数据实例

1、本程序基于前期我的博客文章《MFC用ADO连接ACESS数据库实例(免费源码下载)》 程序功能通过编辑框、组合框实时将数据写入ACESS数据库并在列表控件上显示。 2、在主界面资源视图上加上一个按钮控件、两个静态文本、一个编辑框IDC_EDIT1变量名name、一个组合框IDC_COMBO1变量名…

【Java从入门到精通】Java 流(Stream)、文件(File)和IO

Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。 Java.io 包中的流支持很多种格式&#xff0c;比如&#xff1a;基本类型、对象、本地化字符集等等。 一个流可以理解为一个数据的序列。输入流表示从一个源读取数据&#xff0c;输出流…

021、Python+fastapi,第一个Python项目走向第21步:ubuntu 24.04 docker 安装mysql8、redis(二)

系列文章目录 pythonvue3fastapiai 学习_浪淘沙jkp的博客-CSDN博客https://blog.csdn.net/jiangkp/category_12623996.html 前言 安装redis 我会以三种方式安装&#xff0c; 第一、直接最简单安装&#xff0c;适用于测试环境玩玩 第二、conf配置安装 第三、集群环境安装 一…

ASP.NET视频点播系统的设计与实现

摘 要 本文阐述了基于WEB的交互式视频点播系统的协议原理、软件结构和设计实现。本视频点播系统根据流媒体传输原理&#xff0c;在校园局域网的基础上模拟基于Web的视频点播系统&#xff0c;实现用户信息管理、视频文件的添加、删除、修改及在线播放和搜索功能。本系统是一个…

llama-factory/peft微调千问1.5-7b-chat

目标 使用COIG-CQIA数据集和通用sft数据集对qwen1.5-7b-chat进行sft微调,使用公开dpo数据集进行dpo对齐。学习千问的长度外推方法。 一、训练配置 使用Lora方式, 将lora改为full即可使用全量微调。 具体的参数在 该框架将各个参数、训练配置都封装好了,直接使用脚本,将数…

Redis高并发可用-主从复制,集群

Redis高并发可用 1 复制 默认情况下&#xff0c;Redis都是主节点。每个从节点只能有一个主节点&#xff0c;而主节点可以同时具有多个从节点。复制的数据流是单向的&#xff0c;只能由主节点复制到从节点。 1.1 复制的拓扑结构 一主一从&#xff1a; 主一从结构是最简单的…

【全网最全】2024五一数学建模B题前四问代码多种保奖进阶思路+建模过程+代码+数据处理+论文写作技巧等(后续会更新)

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片&#xff0c;这是获取资料的入口&#xff01; 【全网最全】2024五一数学建模B题前四问代码多种保奖进阶思路建模过程代码数据处理论文写作技巧等&#xff08;后续会更新&#xff09;「首先来看看目前已有…

LeetCode 94.二叉树的中序遍历

题目描述 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root [1] …

R语言学习—1—将数据框中某一列数据改成行名

将数据框中某一列数据改成行名 代码 结果

观察者模式实战:解密最热门的设计模式之一

文章目录 前言一、什么是观察者模式二、Java实现观察者模式2.1 观察者接口2.2 具体观察者2.3 基础发布者2.4 具体发布者2.5 消息发送 三、Spring实现观察者模式3.1 定义事件类3.2 具体观察者3.3 具体发布者3.4 消息发送 总结 前言 随着系统的复杂度变高&#xff0c;我们就会采…

vivado Aurora 8B/10B IP核(9)- CRC、 Aurora 8B/10B内核的时钟接口端口

CRC 模块提供 16 位或 32 位 CRC&#xff0c;用于用户数据。 Aurora 8B/10B 内核的时钟接口端口 从相邻收发器四边形的时钟Xilinx 实现工具可以根据需要对南北路由和引脚交换到收发器时钟输入进行必要的调整&#xff0c;以将时钟从一个四线到另一个。 重要信息&#xff1a;共…

踏上R语言之旅:解锁数据世界的神秘密码(五)

线性与非线性模型及R使用 文章目录 线性与非线性模型及R使用一、数据的分类与模型选择1.变量的取值类型 二、广义线性模型广义线性模型概述Logistic模型 总结 一、数据的分类与模型选择 1.变量的取值类型 因变量记为y&#xff0c;解释变量记为x1&#xff0c;x2,… 因变量y一般…

第三节课,功能2:开发后端用户的管理接口-- postman--debug测试

一、如何使用postman 网址&#xff1a; https://www.postman.com/downloads/ 【Postman小白教程】五分钟学会如何使用Postman~_哔哩哔哩_bilibili postman安装使用_bowser agent在postman哪里-CSDN博客 二、下载后 登录&#xff0c;开始测试 2.1 关于postman 报错&#…

MTEB - Embedding 模型排行榜

文章目录 关于 MTEBMTEB 任务和数据集概览使用 MTEB Pythont 库Installation使用 关于 MTEB MTEB : Massive Text Embedding Benchmark github : https://github.com/embeddings-benchmark/mtebhuggingface : https://huggingface.co/spaces/mteb/leaderboardpaper : https:/…

【Java EE】CAS原理和实现以及JUC中常见的类的使用

˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如…

asyncionetworkxFuncAnimation学习--动态显示计算图的运行情况

asyncio&networkx&FuncAnimation学习--动态显示计算图的运行情况 一.效果二.代码 一.目的 1.动态显示计算图的运行状态(点或边是否已完成) 二.步骤: 1.定义计算图 2.asyncio 并行计算 3.networkx 显示计算图 4.FuncAnimation 动态更新 三.依赖: conda install pygraphv…

数据结构--栈与队列【您的关注是我创作的动力!】

文章目录 栈什么是栈&#xff1f;栈的具体实现 队列什么是队列&#xff1f;队列的实现 栈 什么是栈&#xff1f; 栈也是顺序表的一种&#xff0c;栈的逻辑实现是先进后出&#xff08;后进先出&#xff09;就跟子弹夹一样。 具体逻辑就是它只允许在固定的一端进行数据的插入与…

PHP源码_最新Ai对话系统网站源码 ChatGPT+搭建教程+前后端

基于ChatGPT开发的一个人工智能技术驱动的自然语言处理工具&#xff0c;它能够通过学习和理解人类的语言来进行对话&#xff0c;还能根据聊天的上下文进行互动&#xff0c;真正像人类一样来聊天交流&#xff0c;甚至能完成撰写邮件、视频脚本、文案、翻译、代码&#xff0c;写论…

C# Web控件与数据感应之 CheckBoxList 类

目录 关于数据感应 CheckBoxList 类 范例运行环境 数据源表设计 角色字典表 用户角色表 AutoValueDBList 方法 原理 设计 实现 调用示例 初始化数据 启动查询模式 使用保存模式 小结 关于数据感应 数据感应也即数据捆绑&#xff0c;是一种动态的&#xff0c;We…

【Docker学习】docker version查看版本信息

就像很多应用一样&#xff0c;docker也使用version来查看版本信息。但因为docker包含有不少独立组件&#xff0c;version的作用范围会更广一些。 用法1&#xff1a; docker --version 描述&#xff1a; 输出安装的Docker CLI 的版本号。关于Docker CLI&#xff0c;请访问。 实操…