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、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看所…...
通过源码⼀步⼀步分析 ArrayList 扩容机制
ArrayList 是 Java 中常用的集合类,它底层实现是基于数组的。为了处理元素的动态增加,ArrayList 会在容量不足时进行扩容。以下是通过源码逐步分析 ArrayList 扩容机制的过程。 1. ArrayList 类的基本结构 ArrayList 继承自 AbstractList,实…...
源码分析之Openlayers中默认Controls控件渲染原理
概述 Openlayers 中默认的三类控件是Zoom、Rotate和Attribution 源码分析 defaults方法 Openlayers 默认控件的集成封装在defaults方法中,该方法会返回一个Collection的实例,Collection是一个基于数组封装了一些方法,主要涉及到数组项的添…...
中间件的分类与实践:从消息到缓存
目录 一. 中间件的基本概念 二. 中间件的主要类型 (1)消息中间件(Message-Oriented Middleware, MOM): (2)数据库中间件: (3)Web中间件: &a…...
京东e卡 h5st 4.96
声明: 本文章中所有内容仅供学习交流使用,不用于其他任何目的,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关! 有相关问题请第一时间头像私信联系我删…...
《CSS 知识点》滚动条仅在 hover 时才显示(宽度不改变)
很简单! 滚动条的滑动小方块背景色默认透明,仅在hover时设置背景色; 滚动条的轨道背景色默认透明,仅在hover时设置背景色; /*滚动条的滑动小方块*/ ::-webkit-scrollbar-thumb {background: transparent; } /*hover…...
手里有病理切片+单细胞测序的数据,如何开展医工交叉的研究?
小罗碎碎念 这一期推文研究一个问题:病理如何与单细胞结合? 病理与单细胞的结合,时常出现在今年的各大顶刊中。 关于这一领域的研究,其实19年就开始了。我把部分低质量的文献做了剔除,但是也基本能反应这一领域的受关注…...
力矩扭矩传感器介绍
在机械臂(机器人臂)末端使用的力矩扭矩传感器主要用于测量机械臂末端执行器(例如机械手爪、抓取装置等)所受的扭矩和力。这些传感器对机械臂的控制系统至关重要,能够提供精确的力反馈信息,帮助实现更高效、…...
【Appium】AttributeError: ‘NoneType‘ object has no attribute ‘to_capabilities‘
目录 1、报错内容 2、解决方案 (1)检查 (2)报错原因 (3)解决步骤 3、解决结果 1、报错内容 在PyCharm编写好脚本后,模拟器和appium也是连接成功的,但是运行脚本时报错&…...
QT 中 多线程(备查)
基础 一个线程处理窗口事件,其他线程进行逻辑运算 在QT中使用多线程,需要额外注意的: 1)默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新 2)子线程负责后台…...
第八十六条:在实现serializable接口时要特别谨慎
要想使一个类的实例可被序列化,非常简单,只要在它的声明中加入"implements Serializable"字样即可。虽然使一个类可被序列化的直接开销低到甚至可以忽略不计,但是为了序列化而付出的长期开销往往是实实在在的。 为实现Serializable…...
网站开发的语言有什么/新闻平台发布
Abby: 娇小可爱的女人,文静,令人喜爱,个性甜美。 Aimee: 意为可爱的人。 Alisa: 快乐的姑娘的意思。 Angelia: 天使,传送讯息者。Angelia被描绘为美丽,娇小的女子若不是有著甜美温柔的个性,即是活泼莽撞的女…...
做的网站电脑上跟手机上不一样/google seo是什么意思
✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室 🍊个人信条:格物致知。 ⛄ 内容介绍 Monoamine oxidase A (MAOA) is a mito…...
政府网站的域名/营销型网站建站
匿名对象 匿名对象是指创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量。 创建一个普通对象 Person p new Person(); 创建一个匿名对象 new Person(); 匿名对象的特点 l 创建匿名对象直接使用,没有变量名。 new Person().…...
申请注册公司流程及费用/seo技术培训宁波
这两天一位电商分析师L接连撰文帮当当找买家,另外,再前几日在微信朋友圈也听一好友H说当当找到买主了,这两位都是电商分析圈的资深人士,他们说的内容都与当当在找买主有关。无风不起浪,当当在找买主或者找投资的事很有…...
wordpress能做什么/微信广告平台推广
1,软硬件准备 软件:推荐使用VMwear,我用的是VMwear 10 镜像:CentOS 7 ,如果没有镜像可以去官网下载:https://www.centos.org/download/ 选择一个节点下载CentOS 7: 2.虚拟机准备 1)打开VMwea,点击左上角文…...
简单网站建设/网站查询工具
管道的半双工 管道在双方在内核中共用同一内存区,为了保证数据信息的准确性,所以双方进程读写互斥,且一方写时另一方不可读。 由于双方共享一块缓冲,所以半双工的限制就产生了。 Socket的双工 所谓双工就是两个进程拥有两块缓存…...