判断一棵树是不是平衡二叉树。
思路一:计算出左右子树的深度,然后检查差。递归继续判断左子树和右子树是不是平衡二叉树。
思路二:先计算左子树和右子树是不是平衡二叉树,然后再计算本身是不是平衡二叉树。
关于思路二为什么能比思路一更好,请看代码。
先递归实现树的深度函数:
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;}
这种思路慢是因为:节点被重复计算了。得出 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);}
先遍历和计算左右子树,最后计算本身。不需要重复计算。
/*** 优化:判断是否是平衡二叉树** @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;}}
/*** 测试代码*/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)); // trueconsole.timeEnd(); // 0.594ms// 优化算法:判断是否是平衡二叉树console.time();console.log(isBalanced2(root)); // trueconsole.timeEnd(); // 0.242ms