Leetcode(110)——平衡二叉树

Leetcode(110)——平衡二叉树

题目

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

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

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 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

提示:

  • 树中的节点数在范围 [0, 5000] 内
  • − 1 0 4 -10^4 104 <= Node.val <= 1 0 4 10^4 104

题解

方法一:自顶向下——暴力递归

思路

​​  定义函数 treeheight \texttt{treeheight} treeheight,用于计算二叉树中的以任意一个结点 p p p 为根结点的子树的高度:

treeheight ( p ) = { 0 p  是空结点 max ⁡ ( treeheight ( p . left ) , treeheight ( p . right ) ) + 1 p  是非空结点 \texttt{treeheight}(p) = \begin{cases} 0 & p \text{ 是空结点}\\ \max(\texttt{treeheight}(p.\textit{left}), \texttt{treeheight}(p.\textit{right}))+1 & p \text{ 是非空结点} \end{cases} treeheight(p)={0max(treeheight(p.left),treeheight(p.right))+1p 是空结点p 是非空结点

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

​​  为什么先计算计算左右子树的高度,再判断左子树和右子树是否平衡?
​​  因为计算左右子树的高度判断左右子树是否平衡更快。所以这里应用了“短路效应”以减少部分耗时。

代码实现
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isBalanced(TreeNode* root) {
        if(root == nullptr) return true;
        if(abs(treeheight(root->left) - treeheight(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right)) return true;
        else return false;
    }
    int treeheight(TreeNode* node){
        if(node == nullptr) return 0;
        else return max(treeheight(node->left), treeheight(node->right))+1;
    }
};
// 140ms的原因:
// 140ms:isBalanced(root->left) && abs(treeheight(root->left) - treeheight(root->right)) <= 1 && isBalanced(root->right)
// 4ms:  abs(treeheight(root->left) - treeheight(root->right)) <= 1 && isBalanced(root->left) && isBalanced(root->right)
复杂度分析

时间复杂度:其中 n n n 是二叉树中的结点个数。
​​  ​​  ​​  最坏情况下,二叉树是满二叉树,需要遍历二叉树中的所有结点,时间复杂度是 O ( n ) O(n) O(n)
​​  ​​  ​​  对于结点 p p p,如果它的高度是 d d d,则 treeheight ( p ) \texttt{treeheight}(p) treeheight(p) 最多会被调用 d d d 次(即遍历到它的每一个祖先结点时都会调用一次)。
​​  ​​  ​​  对于平均的情况,一棵树的高度 h h h 满足 O ( h ) = O ( log ⁡ n ) O(h)=O(\log n) O(h)=O(logn),因为 d ≤ h d \leq h dh,所以总时间复杂度为 O ( n log ⁡ n ) O(n \log n) O(nlogn)
  ​​  ​​  对于最坏的情况,二叉树形成链式结构,高度为 O ( n ) O(n) O(n),此时总时间复杂度为 O ( n 2 ) O(n^2) O(n2)
空间复杂度 O ( n ) O(n) O(n),其中 n n n 是二叉树中的结点个数。空间复杂度主要取决于递归调用的层数,递归调用的层数不会超过 n n n

方法二:自底向上

思路

​​  方法一由于是自顶向下递归,因此对于同一个结点,求树高度的函数 treeheight \texttt{treeheight} treeheight 会被重复调用,导致时间复杂度较高。如果使用自底向上的做法,则对于每个结点,求树高度的函数 treeheight \texttt{treeheight} treeheight 只会被调用一次。

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

​​  为什么不直接计算出左右子树的高度再一起判断?
​​  因为 treeheight 耗时挺长的,所以先调用 treeheight 判断其中一棵子树的高度,如果它是平衡树,则再调用 treeheight 判断另一棵子树。这样可以减少一部分耗时。

代码实现
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool isBalanced(TreeNode* root) {
        if(root == nullptr) return true;
        if(treeheight(root) != -1) return true;
        else return false;
    }
    int treeheight(TreeNode* node){
        if(node == nullptr) return 0;
        int left = treeheight(node->left);
        if(left == -1) return -1;
        int right = treeheight(node->right);
        if(right == -1) return -1;
        if(abs(left-right) <= 1) return max(left, right)+1;
        else return -1;
    }
};
复杂度分析

时间复杂度 O ( n ) O(n) O(n),其中 n n n 是二叉树中的结点个数。使用自底向上的递归,每个结点的计算高度和判断是否平衡都只需要处理一次,最坏情况下需要遍历二叉树中的所有结点,因此时间复杂度是 O ( n ) O(n) O(n)
空间复杂度 O ( n ) O(n) O(n),其中 n n n 是二叉树中的结点个数。空间复杂度主要取决于递归调用的层数,递归调用的层数不会超过 n n n

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值