LeetCode面试题04 检查平衡性
题目:
实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。
一、平衡树定义:
二叉树,一种由节点组成的树形数据结构,每个节点最多有两个子节点,分别称作左子节点和右子节点。而平衡二叉树,可不是普通的二叉树,它有着严苛的要求:对于树中的任意一个节点,其两棵子树(左子树和右子树)的高度差不能超过 1。这个定义看似简单,实则暗藏玄机,它关乎二叉树的查找效率、稳定性等诸多性能指标。想象一下,如果一棵二叉树极度不平衡,就如同瘸腿走路,某些操作的耗时会大幅增加,效率大打折扣。
举个例子,在一棵平衡二叉搜索树里,查找一个元素的时间复杂度接近O()。可要是树失衡了,最坏情况下查找时间复杂度能退化成O(
),这差距可就太悬殊了。
二、解题思路拆解
整体思路概述
拿到这道题,要判断一棵二叉树是否平衡,关键在于检查树中每个节点的左右子树高度差是否都不超过 1。所以整体思路是通过遍历二叉树的每个节点,去获取并比较其左右子树的高度,进而得出整棵树是否平衡的结论,通常会采用递归的方式来实现这个过程。
(一)计算子树高度
咱们得先打造一个 “高度测量仪”,也就是一个专门计算以某个节点为根节点的子树高度的函数。递归在这里大展拳脚,其逻辑简洁而巧妙:当节点为空时,好比遇到了树的 “尽头”,高度自然是 0;要是节点非空,那这棵子树的高度就得看它左右 “臂膀”(左右子树)谁更长了,取两者高度最大值,再给它加上 1(把当前节点这一层算上)。以下是用 C 语言展示的代码片段:
//计算树的高度的辅助函数
int treeHeight(struct TreeNode* node) {if (node == NULL) {return 0;}int leftHeight = treeHeight(node->left);int rightHeight = treeHeight(node->right);return (leftHeight > rightHeight? leftHeight : rightHeight) + 1;
}
在这段代码里,先是递归地深挖 node
的左子树高度存进 leftHeight
,再探寻右子树高度存入 rightHeight
,最后掐指一算,挑出大值加 1 返回,完美算出子树高度。
(二)判断节点平衡性与整树遍历
有了测量子树高度的 “神器”,下一步就是打造主函数来宣判二叉树的 “平衡命运” 了。首先要照顾到特殊情况,要是根节点就是空的,那没得说,这棵树妥妥是平衡的,直接返回 true
,皆大欢喜。
碰上根节点非空时,就得严肃起来了。先用刚才的函数量出根节点左右子树各自的高度,要是这俩高度差的绝对值大于 1,那这棵树在根节点这儿就 “崴脚” 了,立马返回 false
,宣判它不平衡。
但事情还没完,即便当前根节点这关过了,它的子树里说不定还有 “定时炸弹” (不平衡的节点)呢。所以得接着递归调用主函数,分别去审查左子树和右子树是否平衡,只有左右子树都稳稳当当、符合平衡标准,这整棵树才算得上是平衡的,故而最终返回对左右子树递归判断结果的逻辑与(&&
)。用代码说话:
bool isBalanced(struct TreeNode* root) {if (root == NULL) {return true;}int leftHeight = treeHeight(root->left);int rightHeight = treeHeight(root->right);if (abs(leftHeight - rightHeight) > 1) {return false;}return isBalanced(root->left) && isBalanced(root->right);
}
三、代码实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>//定义树的结构体
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
};// 构建二叉树节点的函数(辅助函数,方便创建测试用的二叉树)
struct TreeNode* createNode(int val) {struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));newNode->val = val;newNode->left = NULL;newNode->right = NULL;return newNode;
}// 计算树的高度的辅助函数
int treeHeight(struct TreeNode* node) {if (node == NULL) {return 0;}// 递归计算左子树高度int leftHeight = treeHeight(node->left);// 递归计算右子树高度int rightHeight = treeHeight(node->right);// 取左右子树中较大的高度加1(根节点算一层)作为当前节点所在子树的高度return (leftHeight > rightHeight? leftHeight : rightHeight) + 1;
}bool isBalanced (struct TreeNode* root)
{if (root==NULL){return true;}// 计算左子树高度int leftHeight = treeHeight(root->left);// 计算右子树高度int rightHeight = treeHeight(root->right);// 判断当前节点的左右子树高度差是否超过1,若超过则不平衡if (abs(leftHeight - rightHeight) > 1) {return false;}// 递归地判断左子树和右子树是否平衡return isBalanced(root->left) && isBalanced(root->right);
};int main(){
//构建一个二叉树struct TreeNode* root = createNode(3);root->left = createNode(9);root->right = createNode(20);root->right->left=createNode(15);root->right->right=createNode(7);bool result = isBalanced(root);if (result) {printf("该二叉树是平衡二叉树\n");} else {printf("该二叉树不是平衡二叉树\n");}return 0;
}
四、代码实现细节与优化点
上面给出的代码是基于 C 语言结构体实现二叉树节点的经典范例。代码结构清晰,两个函数各司其职,一个专心算高度,一个全力判断平衡。
不过呢,这代码还有优化空间。现在计算子树高度和判断平衡的过程中存在重复计算,每次判断一个节点的平衡性,都要重新完整计算左右子树高度,当树规模大时,计算量冗余严重。优化思路是把高度计算与平衡判断合二为一,一边计算高度一边检查平衡性,一旦发现不平衡就及时止损,不再做无用功。这种改进能大幅削减不必要的计算,提升算法效率。
五、改进代码实现
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>// 定义二叉树节点结构体
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
};// 构建二叉树节点的函数(辅助函数,方便创建测试用的二叉树)
struct TreeNode* createNode(int val) {struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));newNode->val = val;newNode->left = NULL;newNode->right = NULL;return newNode;
}// 优化后的函数,同时计算高度并判断是否平衡,返回值大于等于0表示当前子树的高度,返回 -1表示子树不平衡
int isBalancedAndHeight(struct TreeNode* node) {if (node == NULL) {return 0;}// 递归计算左子树高度并判断平衡性int leftHeight = isBalancedAndHeight(node->left);if (leftHeight == -1) {return -1;}// 递归计算右子树高度并判断平衡性int rightHeight = isBalancedAndHeight(node->right);if (rightHeight == -1) {return -1;}// 检查当前节点的左右子树高度差是否超过1if (abs(leftHeight - rightHeight) > 1) {return -1;}// 返回当前子树高度(左右子树中较大高度 + 1)return (leftHeight > rightHeight? leftHeight : rightHeight) + 1;
}// 判断二叉树是否平衡的主函数,调用优化后的辅助函数进行判断
bool isBalanced(struct TreeNode* root) {return isBalancedAndHeight(root)!= -1;
}int main() {// 构建一个简单的二叉树示例(这里你可以自行修改节点值和结构来测试不同情况)struct TreeNode* root = createNode(3);root->left = createNode(9);root->right = createNode(20);root->right->left=createNode(15);root->right->right=createNode(7);bool result = isBalanced(root);if (result) {printf("该二叉树是平衡二叉树\n");} else {printf("该二叉树不是平衡二叉树\n");}return 0;
}
总结与拓展
判断二叉树是否平衡不仅是一道算法面试高频题,更是深入理解二叉树特性的绝佳契机。通过递归手段巧妙遍历、精准测量、严谨比对,我们能稳稳拿捏二叉树的平衡状况。往后再遇到二叉树相关复杂操作,像是构建平衡二叉搜索树、优化树的存储与查找等,这判断平衡的技巧都能派上大用场。
掌握了二叉树平衡判断,就像是拿到了二叉树世界的一把钥匙,诸多神秘大门将徐徐向你敞开。不管是继续刷题深造,还是实际项目里优化数据结构,都能底气十足、游刃有余。要是你对这篇博客内容有啥疑问、想法,或是独到见解,欢迎随时留言交流,咱们一起在算法海洋破浪前行!
相关文章:
LeetCode面试题04 检查平衡性
题目: 实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。 一、平衡树定义: 二叉树,一种由节点组成的树形数据结构,每…...

oracle归档模式下的快速热备方法-适合小库
在我们的一些小型的oracle生产库中,有些时候我们可以在不停库且不使用rman的情况下实现数据库的热备。该热备的原理是通过控制数据文件块头的scn号在备份时候不变化,进而保证备份的数据文件数据一致性。 一、环境 数据库版本: 数据库需要开启…...

【机器学习】【分子属性预测】——python读取.tar.gz文件(以OC22数据集为例)
1 Pre-knowledge .tar.gz 文件是一种常见的压缩文件格式,它实际上是两种压缩格式的组合:.tar 和 .gz。 .tar:这是“tape archive”的缩写,是一种打包(archiving)文件格式,用于将多个文件和目录…...
Qt中禁止或管理任务栏关闭窗口的行为
一、前言 作为一个合格的桌面程序,应该具备良好的资源释放的要求,即避免软件退出时,软件界面虽然消失,却假死在后台,只能通过任务管理器强行杀死。这意味着,程序无法通过正常操作进行退出,变成…...

docker的网络类型和使用方式
docker的网络类型 5种网络类型 bridge 默认类型,桥接到宿主机docker0的网络,有点类似于VM虚拟机的NAT网络模型。 案例: docker run --rm -itd --network bridge --name wzy666wzy-bridge alpine host host类型,共享宿主机的网络空间&#…...

二维立柱图|积水类问题
三类问题 求总的积水量求水坑的个数求水坑最深的深度 基本思路 我们需要从列的角度来看第 i i i 列是不是有积水,但我们该如何确定第 i i i 列是否是有积水? 方法是事先维护一个前后缀的最大值, L [ i ] L[i] L[i] 和 R [ i ] R[i] R[…...

vue前端实现导出页面为word(两种方法)
将vue页面导出为word文档,不用写模板,直接导出即可。 第一种方法(简单版) 第一步:安装所需依赖 npm install html-docx-js -S npm install file-saver -S第二步:创建容器,页面使用方法(简单版࿱…...

22. Three.js案例-创建旋转的圆环面
22. Three.js案例-创建旋转的圆环面 实现效果 知识点 WebGLRenderer (WebGL渲染器) THREE.WebGLRenderer 是Three.js中最常用的渲染器,用于将场景渲染到WebGL画布上。 构造器 new THREE.WebGLRenderer(parameters) 参数类型描述parametersObject可选参数对象&…...

Elasticsearch:使用阿里 infererence API 及 semantic text 进行向量搜索
在之前的文章 “Elasticsearch 开放推理 API 新增阿里云 AI 搜索支持”,它详细描述了如何使用 Elastic inference API 来针对阿里的密集向量模型,稀疏向量模型, 重新排名及 completion 进行展示。在那篇文章里,它使用了很多的英文…...

Linux WEB服务器的部署及优化
1.用户常用关于web的信息 1.1.什么是www www是world wide web的缩写,及万维网,也就是全球信息广播的意思。 通常说的上网就是使用www来查询用户所需要的信息。 www可以结合文字、图形、影像以及声音等多媒体,超链接的方式将信息以Internet…...

人工智能大模型LLM开源资源汇总(持续更新)
说明 目前是大范围整理阶段,所以存在大量机翻说明,后续会逐渐补充和完善资料,减少机翻并增加说明。 Github上的汇总资源(大部分英文) awesome-production-machine-learning 此存储库包含一系列精选的优秀开源库&am…...

目标跟踪算法:SORT、卡尔曼滤波、匈牙利算法
目录 1 目标检测 2 卡尔曼滤波 3《从放弃到精通!卡尔曼滤波从理论到实践》视频简单学习笔记 3.1 入门 3.2 进阶 3.2.1 状态空间表达式 3.2.2 高斯分布 3.3 放弃 3.4 精通 4 匈牙利算法 5 《【运筹学】-指派问题(匈牙利算法)》视…...

Java版-图论-拓扑排序与有向无环图
拓扑排序 拓扑排序说明 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列…...

GTC2024 回顾 | 优阅达携手 HubSpot 亮相上海,赋能企业数字营销与全球业务增长
从初创企业入门到成长型企业拓展,再到 AI 驱动智能化运营,HubSpot 为企业的每步成长提供了全方位支持。 2024 年 11 月下旬,备受瞩目的 GTC2024 全球流量大会(上海)成功举办。本次大会汇聚了全国内多家跨境出海领域企业…...

eclipse启动的时候,之前一切很正常,但突然报Reason: Failed to determine a suitable driver class的解决
1、之前项目都是启动正常的,然后运行以后发现启动不了了,还会报错: 2、这个Reason: Failed to determine a suitable driver class,说是没有合适的驱动class spring:datasource:url: jdbc:sqlserver://192.168.1.101:1433;databa…...
_tkinter.TclError: can‘t find package tkdnd Unable to load tkdnd library.解决办法
Traceback (most recent call last): File “tkinterdnd2\TkinterDnD.py”, line 55, in _require _tkinter.TclError: can’t find package tkdnd During handling of the above exception, another exception occurred: Traceback (most recent call last): File “1.导入总表…...

VBA高级应用30例应用在Excel中的ListObject对象:向表中添加注释
《VBA高级应用30例》(版权10178985),是我推出的第十套教程,教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开,这套教程案例与理论结合,紧贴“实战”,并做“战术总结”,以…...
folly库Conv类型转换源码解析
1,普通类型转换 例子1: bool boolV = true;EXPECT_EQ(to<bool>(boolV), true);int intV = 42;EXPECT_EQ(to<int>(intV), 42);float floatV = 4.2f;EXPECT_EQ(to<float>(floatV), 4.2f);double doubleV = 0.42;EXPECT_EQ(to<double>(doubleV), 0.42)…...
UE4 骨骼网格体合并及规范
实现代码 // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h" #include "SkeletalMeshMerge.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "AceMeshCom…...

Java版企业电子招标采购系统源业码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis
功能描述 1、门户管理:所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含:招标公告、非招标公告、系统通知、政策法规。 2、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看所…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析
1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具,该工具基于TUN接口实现其功能,利用反向TCP/TLS连接建立一条隐蔽的通信信道,支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式,适应复杂网…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

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

如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...