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。abs
和max
是辅助函数,分别用于计算绝对值和取两个整数中的较大值。
复杂度分析
-
时间复杂度
时间复杂度为 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题目与本文讨论的二叉树平衡性检查最为相似。
相关文章:

LeetCode 110.平衡二叉树(Java/C/Python3/Go实现含注释说明,Easy)
标签 树深度优先搜索递归 题目描述 给定一个二叉树,判断它是否是高度平衡的二叉树。 本题中,一棵高度平衡的二叉树定义为: 一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。 原题:LeetCode 110.平衡二叉树 思路及…...
【SQL】ACID事务与隔离级别
数据库事务 数据库事务具有ACID这4个特性: A:Atomicity,原子性,将所有SQL作为原子工作单元执行,要么全部执行,要么全部不执行;C:Consistency,一致性,事务完…...

深度神经网络中的不确定性研究综述
A.单一确定性方法 对于确定性神经网络,参数是确定的,每次向前传递的重复都会产生相同的结果。对于不确定性量化的单一确定性网络方法,我们总结了在确定性网络中基于单一正向传递计算预测y *的不确定性的所有方法。在文献中,可以找…...
实用的Chrome浏览器命令
Google Chrome 是一款广泛使用的网络浏览器,它提供了许多实用的快捷键和命令,可以帮助用户更高效地浏览网页。以下是一些常用的 Chrome 浏览器命令: 1. 新标签页: Ctrl T (Windows/Linux) 或 Command T (Mac) 2. 关闭当前标签: Ctrl W 或…...
无人作业控制器--4G/5G通信
一、环境 开发环境:ubuntu 22 ros2 humble 发布运行环境:地平线旭日x3派、arm64 4G 模组: 移远EC20模块 5G 模组:移远RG200U-CN 网络通信模组根据需要选择其中一款, 前期我们使用4G模组,后续迭代因为…...

动态规划-两个数组的dp问题2
文章目录 1. 不同的子序列(115)2. 通配符匹配(44) 1. 不同的子序列(115) 题目描述: 状态表示: 根据题意这里的dp数组可以定义为二维,并且dp[i][j]表示字符串t的0到i的…...
如何设置并行度 ——《OceanBase 并行执行》系列 2
并行度(degree of parallelism,简称 DOP),是指在执行过程中所使用的工作线程数量。设计并行执行的初衷在于充分利用多核资源以提升效率。OceanBase 的并行执行框架支持多种设定并行度的方式,既允许用户手动设置&#x…...

python直接发布到网站wordpress之三批量发布图片
在前面的文章中,实现了使用python操作wordpress发布文字内容和图片内容。 python直接发布到网站wordpress之一只发布文字-CSDN博客 python直接发布到网站wordpress之二发布图片-CSDN博客 不过,此时发布图片的数量只能是一张图片。但在实际应用中&…...
C#面:ADO.NET 相对于ADO等主要有什么改进
C# ADO.NET 是微软为.NET平台开发的一套数据访问技术,相对于传统的ADO(ActiveX Data Objects)等,它有以下几个主要改进: 面向对象:ADO.NET 是面向对象的数据访问技术,它使用.NET框架中的类和对…...

web前端学习笔记7-iconfont使用
7. iconfont的使用流程 字体图标使用较多的是阿里巴巴iconfont图标库,它是阿里巴巴体验团队推出的图标库和图标管理平台,提供了大量免费和可定制的矢量图标,以满足网页设计、平面设计、UI设计、应用程序开发和其他创意项目的需求。 官方网站:https://www.iconfont.cn/ 使用…...

国内小白用什么方法充值使用ChatGPT4.0?
首先说一下IOS礼品卡订阅,目前最经济实惠的订阅方式,具体操作步骤 使用IOS设备充值,用 App Stroe 兑换券 1、支付宝地址切换旧金山,在里面买app store 的兑换卷 2、美区Apple ID登陆app store ,充值兑换券 3、IOS设…...
富格林:正确杜绝欺诈实现出金
富格林悉知,现货黄金一直以来都是投资者们追逐的热门品种之一。其安全性和避险特性吸引着广大投资者。但在现货黄金市场中要想实现出金其实并不简单,是需要我们通过一定的技巧和方法去正确杜绝欺诈套路。下面为了帮助广大投资者正确杜绝欺诈实现出金&…...

基于java,SpringBoot和VUE的求职招聘简历管理系统设计
摘要 基于Java, Spring Boot和Vue的求职招聘管理系统是一个为了简化求职者与雇主间互动流程而设计的现代化在线平台。该系统后端采用Spring Boot框架,以便快速搭建具有自动配置、安全性和事务管理等特性的RESTful API服务,而前端则使用Vue.js框架构建动…...
sqlserver数据库日志文件log.ldf文件占用过大清除的办法
sqlserver数据库日志文件log.ldf文件占用过大清除的办法 技术交流 http://idea.coderyj.com/ 1.清除数据库日志的方法 --- 查看数据库日志文件名 USE cs GO SELECT file_id, name,size,* FROM sys.database_files;ps 可以看到其中name字段为数据库日志名称"数据库日志名称…...

【Python小技巧】matplotlib不显示图像竟是numpy惹的祸
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、问题:df.plot() 显示不出图像二、尝试各种解决办法1. 增加matplotlib.use,设定GUI2. 升级matplotlib版本 三、numpy是个重要的库1. …...

【AIGC】1、爆火的 AIGC 到底是什么 | 全面介绍
文章目录 一、AIGC 的简要介绍二、AIGC 的发展历程三、AIGC 的基石3.1 基本模型3.2 基于人类反馈的强化学习3.3 算力支持 四、生成式 AI(Generative AI)4.1 单模态4.1.1 生成式语言模型(Generative Language Models,GLM࿰…...
云计算技术概述_3.云计算的部署方式
根据NIST的定义,云计算从部署模式上看可以分为公有云、社区云、私有云和混合云四种类型。 注:NIST(美国国家标准与技术研究院)是美国商务部下属的一个物理科学实验室和非监管机构。 其任务是促进创新和行业竞争力。 NIST 将其活动…...

简述 BIO 、NIO 模型
BIO : 同步阻塞I/O(Block IO) 服务器实现模式为每一个连接一个线程,即客户端有连接请求时服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,此处可以通过线程池机制进行优化。 impo…...
【Python小练】随机验证码
题目 提示输出含数字、字母的四位随机数,输入提示的验证码进行验证,验证码正确结束程序,验证码错误继续输入。 分析 我们可以通过random模块生成0到9的随机数,也可以通过生成65到90的随机数,将65到90的随机ASCLL码转换…...
《1w实盘and大盘基金预测 day30》
今日预测: 3123-3150-3177 探底回升,震荡上涨,收小红小绿 双创指数后期上涨的幅度也是会大于上证的,四月底的时候就提醒建仓。 关注板块:医疗、地产、电力、证券 这周预测 这周上证指数最高看到3200 继续看涨&#…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

【项目实战】通过多模态+LangGraph实现PPT生成助手
PPT自动生成系统 基于LangGraph的PPT自动生成系统,可以将Markdown文档自动转换为PPT演示文稿。 功能特点 Markdown解析:自动解析Markdown文档结构PPT模板分析:分析PPT模板的布局和风格智能布局决策:匹配内容与合适的PPT布局自动…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...