题目一:
解法一:(递归)
解题思路:
- 二叉树节点的深度:指从根节点到该节点的最长简单路径边的条数或者节点数。
- 二叉树节点的高度:指从该节点到叶子节点的最长简单路径边的条数或者节点数。
- Leetcode 以节点数为主
求深度可以从上到下去查,所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能后序遍历(左右中)
递归三部曲:
- 明确递归函数的参数
参数:当前传入结点
那么如何标记左右子树是否差值大于1呢?
如果当前传入节点为根节点的二叉树已经不是二叉平衡树了,还返回高度的话就没有意义了。
所以如果已经不是二叉平衡树了,可以返回-1 来标记已经不符合平衡树的规则了。
代码如下:
// -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
var getHeight = function(node) {}
- 明确终止条件
递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0
代码如下:
if (node == NULL) {
return 0;
}
- 明确单层递归的逻辑
如何判断以当前传入节点为根节点的二叉树是否是平衡二叉树呢?当然是其左子树高度和其右子树高度的差值。
分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则则返回-1,表示已经不是二叉平衡树了。
var isBalanced = function(root) {
var getHeight = function(cur) {
if (cur === null) return 0
let leftHeight = getHeight(cur.left)
if (leftHeight == -1) return -1
let rightHeight = getHeight(cur.right)
if (rightHeight == -1) return -1
if (Math.abs(leftHeight - rightHeight) > 1) {
return -1
} else {
return 1 + Math.max(leftHeight, rightHeight)
}
}
let isBalanced = getHeight(root)
return isBalanced == -1 ? false : true
};
// 或者
var isBalanced = function(root) {
//还是用递归三部曲 + 后序遍历 左右中 当前左子树右子树高度相差大于1就返回-1
// 1. 确定递归函数参数以及返回值
const getDepth = function(node) {
// 2. 确定递归函数终止条件
if(node === null) return 0;
// 3. 确定单层递归逻辑
let leftDepth = getDepth(node.left); //左子树高度
// 当判定左子树不为平衡二叉树时,即可直接返回-1
if(leftDepth === -1) return -1;
let rightDepth = getDepth(node.right); //右子树高度
// 当判定右子树不为平衡二叉树时,即可直接返回-1
if(rightDepth === -1) return -1;
if(Math.abs(leftDepth - rightDepth) > 1) {
return -1;
} else {
return 1 + Math.max(leftDepth, rightDepth);
}
}
return !(getDepth(root) === -1);
};
解法二:(迭代)
解题思路:在104.二叉树的最大深度 (opens new window)中我们可以使用层序遍历来求深度,但是就不能直接用层序遍历来求高度了,这就体现出求高度和求深度的不同。因为总体上深度是从上到下(层次遍历),高度是从下到上(后序遍历)。
本题的迭代方式可以先定义一个函数,专门用来求高度。
这个函数通过栈模拟的后序遍历找每一个节点的高度(其实是通过求传入节点为根节点的最大深度来求的高度)
然后再用栈来模拟后序遍历,遍历每一个节点的时候,再去判断左右孩子的高度是否符合。
当然此题用迭代法,其实效率很低,因为没有很好的模拟回溯的过程,所以迭代法有很多重复的计算。
总结:通过本题可以了解求二叉树深度 和 二叉树高度的差异,求深度适合用前序遍历,而求高度适合用后序遍历。
虽然理论上所有的递归都可以用迭代来实现,但是有的场景难度可能比较大。
// 获取当前节点的高度
var getHeight = function (curNode) {
let stack = [];
if (curNode !== null) stack.push(curNode); // 压入当前元素
let depth = 0, res = 0;
while (stack.length) {
let node = stack[stack.length - 1]; // 取出栈顶
if (node !== null) {
stack.pop();
stack.push(node); // 中
stack.push(null);
depth++;
node.right && stack.push(node.right); // 右
node.left && stack.push(node.left); // 左
} else {
stack.pop();
node = stack[stack.length - 1];
stack.pop();
depth--;
}
res = res > depth ? res : depth;
}
return res;
}
var isBalanced = function (root) {
if (root === null) return true;
let stack = [root];
while (stack.length) {
let node = stack[stack.length - 1]; // 取出栈顶
stack.pop();
if (Math.abs(getHeight(node.left) - getHeight(node.right)) > 1) {
return false;
}
node.right && stack.push(node.right);
node.left && stack.push(node.left);
}
return true;
};