《程序员面试金典(第6版)》面试题 04.04. 检查平衡性
创始人
2024-06-03 01:47:05
0

题目描述

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

示例 1:

  • 给定二叉树 [3,9,20,null,null,15,7]
    3/ \9  20/  \15   7
  • 返回 true 。

示例 2:

  • 给定二叉树 [1,2,2,3,3,null,null,4,4]
      1/ \2   2/ \3   3/ \
4   4
  • 返回 false 。

解题思路与代码

自底向上的递归

为什么说是自底而上的递归呢?首先,我们先递归到达二叉树叶子节点,由叶子节点开始做逻辑判断。然后逐步向上返回判断的结果,最后在二叉树的顶部,我们就根据底部传来的结果去做出判断,到达是返回false,还是true。

那我们判断的逻辑是什么呢?
首先我们肯定是要去写递归函数的。由于主函数是一个bool类型的函数,它是要返回true,或false。而我想的逻辑是判断子节点的高度差,那返回的肯定是个int。所以不能在主函数里写递归,要另写一个递归函数。

我们在主函数外写的递归函数的返回类型是int。然后参数呢,是一个TreeNode* 的类型。确定了递归函数的返回类型,与要传入的参数。我们来想想如何结束每一层的递归。那我们会传入一个节点。我们要拿这个节点的左右子节点去递归判断。首当其冲的结束条件就是这个节点它不能为nullptr,如果为空,就直接返回0。

为了减少递归的次数,我们再补充一条结束条件。如果该节点的左右子节点都为空,那我们就返回1。

写完了结束条件后,我们现在可以来仔细想想递归的单层逻辑怎么去写了。首先,设置两个int类型的变量,left,right。
它们分别将传入节点的左右子节点拿去递归。所以 left = root->left ,right = root->right

那逻辑其实就是从判读每个节点的左右子树的高度差嘛,如果高度差大于1,我们就直接返回 -1这就是最重要的逻辑
那代码表示,就是在left与right处都进行判断,才能达到这个效果。

最后,如果值都正常的话,返回 1 + max(left,right)就行了。

具体的实现,请看下面的代码:

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/
class Solution {
public:bool isBalanced(TreeNode* root) {if(root == nullptr) return true;int left = height(root->left);int right = height(root->right);if(left == -1 || right == -1) return false;if(abs(left - right) > 1) return false;return true;}int height (TreeNode* root){if(root == nullptr) return 0;if(root->left == nullptr && root->right == nullptr) return 1;int left = height(root->left);if(left == -1) return -1;int right = height(root->right);if(right == -1) return -1;if(abs(left - right) > 1) return -1;return 1 + max(left,right);}};

在这里插入图片描述

复杂度分析

时间复杂度:O(n),其中n是二叉树的节点个数。最坏情况下,我们需要遍历完整个二叉树所有节点一遍,才能得出最终的结论。所以时间复杂度是O(n)。

空间复杂度:O(m),其中m是二叉树的高度。也就是我们需要递归的层数。

从顶部向下的递归

那为什么要叫从顶向下的递归呢?这是因为,我们从顶部就开始做运算。一遍一遍的向叶子节点去做递归。等到叶子节点的图中,或到叶子节点了,就会出现结果。我们再将结果一层层的返回出来。由于计算是从上至下的,所以叫做从顶向下的递归。

这边直接给出代码吧,我自己就不深究这种做法了,因为这种做法的时间复杂度为O(n2),比我自己的代码要差很多。

这里贴出具体的代码:

class Solution {
public:int height(TreeNode* root) {if (root == NULL) {return 0;} else {return max(height(root->left), height(root->right)) + 1;}}bool isBalanced(TreeNode* root) {if (root == NULL) {return true;} else {return abs(height(root->left) - height(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right);}}
};

复杂度分析

该代码的时间复杂度为O(n^2),其中n是树中节点的个数,因为最坏情况下需要遍历整棵树来判断平衡性,每次递归都会访问左右子树并返回高度,递归次数最多是n层,所以每次调用height()函数产生 O (n^2) 时间复杂度。

该代码的空间复杂度取决于递归调用栈的深度,最坏情况下,二叉树是完全不平衡的,例如每个结点都只有右子结点,此时将递归n次,即树的高度为n,此时空间复杂度为O(n)

总结

这道题,我做了好多遍了。现在已经能一遍过了,对于刚刚学做二叉树的小伙伴们来说,可能还是有些难度的。

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...