[路飞]算法:判断平衡二叉树

81 阅读3分钟

110. 平衡二叉树

正题

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

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

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

示例 1:

image.png

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

示例 2:

image.png

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

示例 3:

输入: root = []
输出: true

解析

判断二叉树的平衡一定是基于计算二叉树深度的。如何求得某个节点开始的深度是解题的核心。所以我们先探讨一下深度优先遍历的原理和方法。

image.png

如图,给定一颗二叉树,求该二叉树的深度,应该怎么做呢?

我们可以认为,root节点是第一层,深度为1, root.left 和 root.right 的深度都是2。也就是说如果当前节点有 left 或者 有 right ,那么我们就可以给他的深度 +1。并且二叉树的深度是以最大深度来决定的。

所以我们有了求深度的基本原则:

  • 如果该节点没有子节点,那么他的深度就是它本身,就是1

  • 如果该节点有子节点,那么深度在1的基础上再 +1

  • 如果节点不存在,那么高度就不存在,那么高度就是 + 0

  • 最大深度为二叉树深度

不难想到,我们应该使用递归的方式去求深度。

定义获取某节点深度的 getHeight 方法:

var getHeight = function (root) {
    if (!root) {
        return 0 // root 不存在那么这个节点高度就是 0 
    }
    if (!root.left && !root.right) {
       return 1 // 如果该节点没有子节点,那么他的深度就是它本身,就是1
    }
    // 继续将 左节点和右节点进行递归,求的高度,并且 加上本身自身高度
    return Math.max(getHeight(root.left), getHeight(root.right)) + 1
}

实际上也可以从子节点的角度去考虑,假如我们的递归从子节点开始考虑的话,也可以是写成这样的:

var getHeight = function (child) {
    if (!child) { // 记住这个 child 是子节点
        return 1 // 没有子节点,那深度就是 1
    }
    return Math.max(getHeight(child.left) , getHeight(child.right)) + 1
}

1.gif

求得二叉树深度之后,我们可以通过三个条件来判断是否是平衡二叉树了:

  1. root 的左节点深度 和 root 右节点深度之差的绝对值 <= 1

  2. root 的左节点是也是平衡二叉树

  3. root 的右节点也是平衡二叉树

所以我们最终返回的判断条件应该是这样的:

return Math.abs(getHeight(root.left) - getHeight(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right)

最终完整代码:

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {boolean}
 */

var getHeight = function (child) {
    if (!child) { // 记住这个 root 是子节点
        return 1 // 没有子节点,那深度就是 1
    }
    return Math.max(getHeight(child.left) , getHeight(child.right)) + 1
}

// 两种方案求 深度都可以
// var getHeight = function (root) {
//     if (!root) {
//         return 0
//     }
//    if (!root.left && !root.right) {
//        return 1
//    }
//    return Math.max(getHeight(root.left), getHeight(root.right)) + 1
// }


var isBalanced = function(root) {
    if (!root) {
        return true
    }
    return Math.abs(getHeight(root.left) - getHeight(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right)
};

求二叉树深度是一道很基础的算法题,但是要说明白他的原理还是比较难的,只是希望能帮到大家去解决这个问题。