1. 题目描述

判断一棵树是不是平衡二叉树。

2. 思路分析

思路一:计算出左右子树的深度,然后检查差。递归继续判断左子树和右子树是不是平衡二叉树。

思路二:先计算左子树和右子树是不是平衡二叉树,然后再计算本身是不是平衡二叉树。

关于思路二为什么能比思路一更好,请看代码。

3. 代码实现

3.1 树的深度

先递归实现树的深度函数:

class Node {
  /**
   *
   * @param {Number} value
   * @param {Node} left
   * @param {Node} right
   */
  constructor(value, left, right) {
    this.value = value;
    this.left = left;
    this.right = right;
  }
}

/**
 * 获取二叉树的深度
 *
 * @param {Node} root
 */
function treeDepth(root) {
  if (!root) {
    return 0;
  }

  const leftDepth = treeDepth(root.left);
  const rightDepth = treeDepth(root.right);
  return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

3.2 思路一

这种思路慢是因为:节点被重复计算了。得出 leftDepth 计算了一遍 root.left ,最后还要再调用自身计算 root.left。尤其是叶子节点,会造成很多的计算浪费。

/**
 * 判断是否是平衡二叉树
 *
 * @param {Node} root
 */
function isBalanced(root) {
  if (!root) {
    return true;
  }

  const leftDepth = treeDepth(root.left);
  const rightDepth = treeDepth(root.right);
  const diff = Math.abs(leftDepth - rightDepth);
  if (diff > 1) {
    return false;
  }

  return isBalanced(root.left) && isBalanced(root.right);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

3.3 思路二

先遍历和计算左右子树,最后计算本身。不需要重复计算。

/**
 * 优化:判断是否是平衡二叉树
 *
 * @param {Node} root
 * @param {Object} obj
 */
function isBalanced2(root, obj = {}) {
  if (!root) {
    obj.depth = 0;
    return true;
  }

  const left = {},
    right = {};
  if (isBalanced2(root.left, left) && isBalanced2(root.right, right)) {
    const diff = Math.abs(left.depth - right.depth);
    if (diff > 1) {
      return false;
    }

    obj.depth = 1 + (left.depth > right.depth ? left.depth : right.depth);
    return true;
  } else {
    return false;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

3.4 测试

/**
 * 测试代码
 */
const root = new Node(
  1,
  new Node(2, new Node(4), new Node(5, new Node(7))),
  new Node(3, null, new Node(6))
);

// 测试树的深度
console.log(treeDepth(root)); // output: 4

// 判断是否是平衡二叉树
console.time();
console.log(isBalanced(root)); // true
console.timeEnd(); // 0.594ms

// 优化算法:判断是否是平衡二叉树
console.time();
console.log(isBalanced2(root)); // true
console.timeEnd(); // 0.242ms
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21