「前端刷题」110. 平衡二叉树

213 阅读1分钟

「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」。

题目

链接:leetcode-cn.com/problems/ba…

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

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

一个二叉树_每个节点 _的左右两个子树的高度差的绝对值不超过 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]
  • -104 <= Node.val <= 104

思路1

解题思路: 自顶向下的比较每个节点的左右子树的最大高度差,如果二叉树中每个节点的左右子树最大高度差小于等于 1 ,即每个子树都平衡时,此时二叉树才是平衡二叉树

代码实现:

var isBalanced = function (root) {
  if(!root) return true
  return Math.abs(depth(root.left) - depth(root.right)) <= 1
        && isBalanced(root.left)
        && isBalanced(root.right)
}
var depth = function (node) {
    if(!node) return -1
    return 1 + Math.max(depth(node.left), depth(node.right))
}

复杂度分析:

  • 时间复杂度:O(nlogn),计算 depth 存在大量冗余操作
  • 空间复杂度:O(n)

思路2

解题思路: 利用后续遍历二叉树(左右根),从底至顶返回子树最大高度,判定每个子树是不是平衡树 ,如果平衡,则使用它们的高度判断父节点是否平衡,并计算父节点的高度,如果不平衡,返回 -1

遍历比较二叉树每个节点 的左右子树深度:

  • 比较左右子树的深度,若差值大于 1 则返回一个标记 -1 ,表示当前子树不平衡
  • 左右子树有一个不是平衡的,或左右子树差值大于 1 ,则二叉树不平衡
  • 若左右子树平衡,返回当前树的深度(左右子树的深度最大值 +1

代码实现:

var isBalanced = function (root) {
    return balanced(root) !== -1
};
var balanced = function (node) {
    if (!node) return 0
    const left = balanced(node.left)
    const right = balanced(node.right)
    if (left === -1 || right === -1 || Math.abs(left - right) > 1) {
        return -1
    }
    return Math.max(left, right) + 1
}

复杂度分析:

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

思路2

  • 暴力解法的解题思路是遍历二叉树,然后对每一个节点计算左右的最大高度。但是计算一棵二叉树的最大深度也需要递归遍历这棵树的所有节点,如果对每个节点都算一遍最大深度,时间复杂度是比较高的。
  • 反向思考的思路是:只计算一次最大深度,计算的过程中在后序遍历位置顺便判断二叉树是否平衡:
  • 对于每个节点,先算出来左右子树的最大高度,然后在后序遍历的位置根据左右子树的最大高度判断平衡性。

/**
 * @param {TreeNode} root
 * @return {boolean}
 */
var isBalanced = function (root) {
  // 记录二叉树是否平衡
  let flag = true;
  const maxDepth = (root) => {
    if (root == null) return 0;
    let leftMaxDepth = maxDepth(root.left);
    let rightMaxDepth = maxDepth(root.right);
    // 如果左右最大深度大于 1,就不是平衡二叉树
    if (Math.abs(rightMaxDepth - leftMaxDepth) > 1) {
      flag = false;
    }
    return 1 + Math.max(leftMaxDepth, rightMaxDepth);
  };
  maxDepth(root);
  return flag;
};