平衡二叉树(简单难度)

简介: 平衡二叉树(简单难度)

题目概述(简单难度)

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1

示例 1:


输入:root = [3,9,20,null,null,15,7]
输出:true

示例 2:


输入:root = [1,2,2,3,3,null,null,4,4]
输出:false

示例3:

输入:root = []
输出:true

题目链接

点我进入leetcode

思路与代码

思路1

这道题目的思路也是非常简单的:

平衡二叉树如果要平衡,一定是每个节点的高度差的绝对值不能超过1

所以这道题目的思路是这样的:

1:首先判断当前节点的左树和有树的高度差是否小于等于1

2:然后再判断这个节点的左树是否平衡

3:然后再判断这个节点的右树是否平衡


具体做法类似于二叉树的前序遍历,即对于当前遍历到的节点,首先计算左右子树的高度,如果左右子树的高度差是否不超过 1,再分别递归地遍历左右子节点,并判断左子树和右子树是否平衡。这是一个自顶向下的递归的过程


这里需要用到递归以及求高度的函数.

代码1

class Solution {
    public int getHeight(TreeNode node) {
        if(node == null) {
            return 0;
        }
        int leftheight = getHeight(node.left);
        int rightheight = getHeight(node.right);
        return leftheight > rightheight ?
                leftheight + 1 : rightheight + 1;
    }
    public boolean isBalanced(TreeNode root) {
        if(root == null) {
            return true;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        //注意是三个条件都要同时满足,使用逻辑与
        return Math.abs(leftHeight-rightHeight) <= 1 
        && isBalanced(root.left) && isBalanced(root.right);
    }
}

我之前的问题是把这三个都要满足的条件分开进行了判断,没有使用逻辑与,总有测试用例过不去.

对于这份代码:

其时间复杂度为O(N 2 N^{2}N

2

),因为对于每一个节点求其高度的空间复杂度为O(N),一共有N个节点,所以时间复杂度为O(N 2 N^{2}N

2

空间复杂度为O(N)其中 N是二叉树中的节点个数。空间复杂度主要取决于递归调用的层数,递归调用的层数取决于我们的高度(或者是深度),递归调用的层数不会超过 N,最坏情况下,二叉树的高度等于节点数,所以说递归调用的层数是小于等于N的,

思路2

思路1中的代码的时间复杂度为O(N 2 N^{2}N

2

),但是我们还可以继续优化,将时间复杂度优化为O(N),具体方式如下:


代码2

class Solution {
    public int height(TreeNode node) {
        if(node == null) {
            return 0;
        }
        int leftHeight = height(node.left);
        int rightHeight = height(node.right);
      //当每次遍历完成后左子树的返回值和右子树的返回值如果都大于0,说明最终的在根节点处的返回值也一定是大于0的
        if(leftHeight >=0 && rightHeight >=0 && Math.abs(leftHeight-rightHeight) <= 1) {
            return Math.max(leftHeight,rightHeight) + 1; 
        }else {
            return -1;
        }
    }
    public boolean isBalanced(TreeNode root) {
        if(root == null) {
            return true;
        }
        if(height(root) >= 0) {
            return true;
        }
        return false;
    }
}

方法1中由于是自顶向下递归,因此对于同一个节点,函数 getHeight会被重复调用,导致时间复杂度较高。如果使用自底向上的做法,则对于每个节点,函数height只会被调用一次。


自底向上递归的做法类似于后序遍历,对于当前遍历到的节点,先递归地判断其左右子树是否平衡,再判断以当前节点为根的子树是否平衡。如果一棵子树是平衡的,则返回其高度(高度一定是非负整数),否则返回 -1。如果存在一棵子树不平衡,则整个二叉树一定不平衡。

递归返回值

当节点root 左 / 右子树的高度差 < 2 :则返回以节点root为根节点的子树的最大高度,即节点 root 的左右子树中最大高度加 1 ( max(left, right) + 1 );

当节点root 左 / 右子树的高度差 ≥2 :则返回 -1,代表 此子树不是平衡树 。

递归终止条件:

当越过叶子节点时,返回高度 0 ;

当左(右)子树高度 left== -1 时,代表此子树的 左(右)子树 不是平衡树,因此直接返回 -1 ;

左右子树高度等于-1(也就是在根节点1处的时候,leftHeight和rightHeight的值此时都为-1)的情况就是如下情况:

2.png

总结下来就是当每次遍历完成后左子树的返回值和右子树的返回值如果都大于0,说明最终的在根节点处的返回值也一定是小于等于1的,假如其中左子树的返回值或者右子树的返回值的其中一个值为-1,那么最终某个根节点的返回值也一定是大于1的,那么就不是一个平衡二叉树了.


对于这个算法来说:

时间复杂度:其中 n 是二叉树中的节点个数。使用自底向上的递归,每个节点的计算高度和判断是否平衡都只需要处理一次,而之前的做法每个需要判断两次,所以时间复杂度为O(N 2 N^{2}N

2

),方法2中最坏情况下需要遍历二叉树中的所有节点,因此时间复杂度是 O(n)。

空间复杂度:O(n),其中 n 是二叉树中的节点个数。空间复杂度主要取决于递归调用的层数,递归调用的层数不会超过 n。

总结

考察对于二叉树的掌握,此道题目采用了两种方法来做,也是非常经典的一道题目,面试的时候建议直接做出O(N)的解法.


相关文章
|
2月前
|
存储 缓存 算法
如何提高二叉树遍历算法的效率?
选择合适的遍历算法,如按层次遍历树时使用广度优先搜索(BFS),中序遍历二叉搜索树以获得有序序列。优化数据结构,如使用线索二叉树减少空指针判断,自定义节点类增加辅助信息。利用递归与非递归的特点,避免栈溢出问题。多线程并行遍历提高速度,注意线程安全。缓存中间结果,避免重复计算。预先计算并存储信息,提高遍历效率。综合运用这些方法,提高二叉树遍历算法的效率。
77 5
|
5月前
|
搜索推荐
九大排序算法时间复杂度、空间复杂度、稳定性
九大排序算法的时间复杂度、空间复杂度和稳定性,提供了对各种排序方法效率和特性的比较分析。
240 1
|
6月前
|
算法 测试技术 C++
【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术
【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术
46 2
|
7月前
|
算法 架构师 NoSQL
「AVL平衡树专项」带你领略常用的AVL树与红黑树的奥秘(规则篇)
原先属于X的空结点被A“继承”。如果被删除结点是黑色结点,则可能造成树的黑色高度变化。
459 0
|
8月前
|
存储 算法
快速排序:非递归的优势与性能详解
快速排序:非递归的优势与性能详解
69 1
|
8月前
|
算法 前端开发
前端算法-平衡二叉树
前端算法-平衡二叉树
|
机器学习/深度学习 存储 人工智能
代码随想录训练营day21| 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先...
代码随想录训练营day21| 530.二叉搜索树的最小绝对差 501.二叉搜索树中的众数 236. 二叉树的最近公共祖先...
二叉搜索树的最近公共祖先(简单难度)
二叉搜索树的最近公共祖先(简单难度)
85 0
二叉搜索树的最近公共祖先(简单难度)
二叉搜索树的第k大节点(简单难度)
二叉搜索树的第k大节点(简单难度)
80 0
二叉搜索树的第k大节点(简单难度)
|
存储
二叉搜索树与双向链表(中等难度)(好题目)
二叉搜索树与双向链表(中等难度)(好题目)
125 0
二叉搜索树与双向链表(中等难度)(好题目)