当前位置: 首页 > news >正文

LeetCode面试题04 检查平衡性

题目:

实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个节点,其两棵子树的高度差不超过 1。

一、平衡树定义:

二叉树,一种由节点组成的树形数据结构,每个节点最多有两个子节点,分别称作左子节点和右子节点。而平衡二叉树,可不是普通的二叉树,它有着严苛的要求:对于树中的任意一个节点,其两棵子树(左子树和右子树)的高度差不能超过 1。这个定义看似简单,实则暗藏玄机,它关乎二叉树的查找效率、稳定性等诸多性能指标。想象一下,如果一棵二叉树极度不平衡,就如同瘸腿走路,某些操作的耗时会大幅增加,效率大打折扣。

举个例子,在一棵平衡二叉搜索树里,查找一个元素的时间复杂度接近O(\log n)。可要是树失衡了,最坏情况下查找时间复杂度能退化成O(n),这差距可就太悬殊了。

二、解题思路拆解

整体思路概述

拿到这道题,要判断一棵二叉树是否平衡,关键在于检查树中每个节点的左右子树高度差是否都不超过 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 检查平衡性

题目&#xff1a; 实现一个函数&#xff0c;检查二叉树是否平衡。在这个问题中&#xff0c;平衡树的定义如下&#xff1a;任意一个节点&#xff0c;其两棵子树的高度差不超过 1。 一、平衡树定义&#xff1a; 二叉树&#xff0c;一种由节点组成的树形数据结构&#xff0c;每…...

oracle归档模式下的快速热备方法-适合小库

在我们的一些小型的oracle生产库中&#xff0c;有些时候我们可以在不停库且不使用rman的情况下实现数据库的热备。该热备的原理是通过控制数据文件块头的scn号在备份时候不变化&#xff0c;进而保证备份的数据文件数据一致性。 一、环境 数据库版本&#xff1a; 数据库需要开启…...

【机器学习】【分子属性预测】——python读取.tar.gz文件(以OC22数据集为例)

1 Pre-knowledge .tar.gz 文件是一种常见的压缩文件格式&#xff0c;它实际上是两种压缩格式的组合&#xff1a;.tar 和 .gz。 .tar&#xff1a;这是“tape archive”的缩写&#xff0c;是一种打包&#xff08;archiving&#xff09;文件格式&#xff0c;用于将多个文件和目录…...

Qt中禁止或管理任务栏关闭窗口的行为

一、前言 作为一个合格的桌面程序&#xff0c;应该具备良好的资源释放的要求&#xff0c;即避免软件退出时&#xff0c;软件界面虽然消失&#xff0c;却假死在后台&#xff0c;只能通过任务管理器强行杀死。这意味着&#xff0c;程序无法通过正常操作进行退出&#xff0c;变成…...

docker的网络类型和使用方式

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

二维立柱图|积水类问题

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

vue前端实现导出页面为word(两种方法)

将vue页面导出为word文档&#xff0c;不用写模板&#xff0c;直接导出即可。 第一种方法(简单版) 第一步&#xff1a;安装所需依赖 npm install html-docx-js -S npm install file-saver -S第二步&#xff1a;创建容器&#xff0c;页面使用方法&#xff08;简单版&#xff1…...

22. Three.js案例-创建旋转的圆环面

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

Elasticsearch:使用阿里 infererence API 及 semantic text 进行向量搜索

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

Linux WEB服务器的部署及优化

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

人工智能大模型LLM开源资源汇总(持续更新)

说明 目前是大范围整理阶段&#xff0c;所以存在大量机翻说明&#xff0c;后续会逐渐补充和完善资料&#xff0c;减少机翻并增加说明。 Github上的汇总资源&#xff08;大部分英文&#xff09; awesome-production-machine-learning 此存储库包含一系列精选的优秀开源库&am…...

目标跟踪算法:SORT、卡尔曼滤波、匈牙利算法

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

Java版-图论-拓扑排序与有向无环图

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

GTC2024 回顾 | 优阅达携手 HubSpot 亮相上海,赋能企业数字营销与全球业务增长

从初创企业入门到成长型企业拓展&#xff0c;再到 AI 驱动智能化运营&#xff0c;HubSpot 为企业的每步成长提供了全方位支持。 2024 年 11 月下旬&#xff0c;备受瞩目的 GTC2024 全球流量大会&#xff08;上海&#xff09;成功举办。本次大会汇聚了全国内多家跨境出海领域企业…...

eclipse启动的时候,之前一切很正常,但突然报Reason: Failed to determine a suitable driver class的解决

1、之前项目都是启动正常的&#xff0c;然后运行以后发现启动不了了&#xff0c;还会报错&#xff1a; 2、这个Reason: Failed to determine a suitable driver class&#xff0c;说是没有合适的驱动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例》&#xff08;版权10178985&#xff09;&#xff0c;是我推出的第十套教程&#xff0c;教程是专门针对高级学员在学习VBA过程中提高路途上的案例展开&#xff0c;这套教程案例与理论结合&#xff0c;紧贴“实战”&#xff0c;并做“战术总结”&#xff0c;以…...

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、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…...

通过源码⼀步⼀步分析 ArrayList 扩容机制

ArrayList 是 Java 中常用的集合类&#xff0c;它底层实现是基于数组的。为了处理元素的动态增加&#xff0c;ArrayList 会在容量不足时进行扩容。以下是通过源码逐步分析 ArrayList 扩容机制的过程。 1. ArrayList 类的基本结构 ArrayList 继承自 AbstractList&#xff0c;实…...

源码分析之Openlayers中默认Controls控件渲染原理

概述 Openlayers 中默认的三类控件是Zoom、Rotate和Attribution 源码分析 defaults方法 Openlayers 默认控件的集成封装在defaults方法中&#xff0c;该方法会返回一个Collection的实例&#xff0c;Collection是一个基于数组封装了一些方法&#xff0c;主要涉及到数组项的添…...

中间件的分类与实践:从消息到缓存

目录 一. 中间件的基本概念 二. 中间件的主要类型 &#xff08;1&#xff09;消息中间件&#xff08;Message-Oriented Middleware, MOM&#xff09;&#xff1a; &#xff08;2&#xff09;数据库中间件&#xff1a; &#xff08;3&#xff09;Web中间件&#xff1a; &a…...

京东e卡 h5st 4.96

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 有相关问题请第一时间头像私信联系我删…...

《CSS 知识点》滚动条仅在 hover 时才显示(宽度不改变)

很简单&#xff01; 滚动条的滑动小方块背景色默认透明&#xff0c;仅在hover时设置背景色&#xff1b; 滚动条的轨道背景色默认透明&#xff0c;仅在hover时设置背景色&#xff1b; /*滚动条的滑动小方块*/ ::-webkit-scrollbar-thumb {background: transparent; } /*hover…...

手里有病理切片+单细胞测序的数据,如何开展医工交叉的研究?

小罗碎碎念 这一期推文研究一个问题&#xff1a;病理如何与单细胞结合&#xff1f; 病理与单细胞的结合&#xff0c;时常出现在今年的各大顶刊中。 关于这一领域的研究&#xff0c;其实19年就开始了。我把部分低质量的文献做了剔除&#xff0c;但是也基本能反应这一领域的受关注…...

力矩扭矩传感器介绍

在机械臂&#xff08;机器人臂&#xff09;末端使用的力矩扭矩传感器主要用于测量机械臂末端执行器&#xff08;例如机械手爪、抓取装置等&#xff09;所受的扭矩和力。这些传感器对机械臂的控制系统至关重要&#xff0c;能够提供精确的力反馈信息&#xff0c;帮助实现更高效、…...

【Appium】AttributeError: ‘NoneType‘ object has no attribute ‘to_capabilities‘

目录 1、报错内容 2、解决方案 &#xff08;1&#xff09;检查 &#xff08;2&#xff09;报错原因 &#xff08;3&#xff09;解决步骤 3、解决结果 1、报错内容 在PyCharm编写好脚本后&#xff0c;模拟器和appium也是连接成功的&#xff0c;但是运行脚本时报错&…...

QT 中 多线程(备查)

基础 一个线程处理窗口事件&#xff0c;其他线程进行逻辑运算 在QT中使用多线程&#xff0c;需要额外注意的&#xff1a; 1&#xff09;默认的线程在Qt中称之为窗口线程&#xff0c;也叫主线程&#xff0c;负责窗口事件处理或者窗口控件数据的更新 2&#xff09;子线程负责后台…...

第八十六条:在实现serializable接口时要特别谨慎

要想使一个类的实例可被序列化&#xff0c;非常简单&#xff0c;只要在它的声明中加入"implements Serializable"字样即可。虽然使一个类可被序列化的直接开销低到甚至可以忽略不计&#xff0c;但是为了序列化而付出的长期开销往往是实实在在的。 为实现Serializable…...

网站开发的语言有什么/新闻平台发布

Abby: 娇小可爱的女人&#xff0c;文静&#xff0c;令人喜爱&#xff0c;个性甜美。 Aimee: 意为可爱的人。 Alisa: 快乐的姑娘的意思。 Angelia: 天使&#xff0c;传送讯息者。Angelia被描绘为美丽&#xff0c;娇小的女子若不是有著甜美温柔的个性&#xff0c;即是活泼莽撞的女…...

做的网站电脑上跟手机上不一样/google seo是什么意思

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 ⛄ 内容介绍 Monoamine oxidase A (MAOA) is a mito…...

政府网站的域名/营销型网站建站

匿名对象 匿名对象是指创建对象时&#xff0c;只有创建对象的语句&#xff0c;却没有把对象地址值赋值给某个变量。 创建一个普通对象 Person p new Person(); 创建一个匿名对象 new Person(); 匿名对象的特点 l 创建匿名对象直接使用&#xff0c;没有变量名。 new Person().…...

申请注册公司流程及费用/seo技术培训宁波

这两天一位电商分析师L接连撰文帮当当找买家&#xff0c;另外&#xff0c;再前几日在微信朋友圈也听一好友H说当当找到买主了&#xff0c;这两位都是电商分析圈的资深人士&#xff0c;他们说的内容都与当当在找买主有关。无风不起浪&#xff0c;当当在找买主或者找投资的事很有…...

wordpress能做什么/微信广告平台推广

1&#xff0c;软硬件准备 软件&#xff1a;推荐使用VMwear&#xff0c;我用的是VMwear 10 镜像&#xff1a;CentOS 7 ,如果没有镜像可以去官网下载&#xff1a;https://www.centos.org/download/ 选择一个节点下载CentOS 7&#xff1a; 2.虚拟机准备 1)打开VMwea,点击左上角文…...

简单网站建设/网站查询工具

管道的半双工 管道在双方在内核中共用同一内存区&#xff0c;为了保证数据信息的准确性&#xff0c;所以双方进程读写互斥&#xff0c;且一方写时另一方不可读。 由于双方共享一块缓冲&#xff0c;所以半双工的限制就产生了。 Socket的双工 所谓双工就是两个进程拥有两块缓存…...