每天 3 分钟,走上算法的逆袭之路。
前文合集
代码仓库
GitHub: https://github.com/meteor1993/LeetCode
Gitee: https://gitee.com/inwsy/LeetCode
题目:将有序数组转换为二叉搜索树
题目来源:https://leetcode-cn.com/problems/balanced-binary-tree/
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点的左右两个子树的高度差的绝对值不超过 1 。
示例 1:
给定二叉树 [3,9,20,null,null,15,7]
3
/
9 20
/
15 7
返回 true
。
示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
1
/
2 2
/
3 3
/
4 4
返回 false
。
解题思路
这道题题目上已经给的很清晰了,要我们判断一个树是否是一个高度平衡二叉树,而高度平衡二叉树的定义是每个节点的两个子树高度差的绝对值不超过 1 。
看到这道题不知道各位有啥想法,我的想法就比较粗暴了,前面我记得有好几道题都介绍过怎么求一个二叉树的高度,我只需要遍历这个树上的每一个节点,然后分别获取这个节点的左右子树高度,看看差的绝对值有没有超过 1 。
获取一个二叉树高度有两种方案,一种是递归,一种是迭代。
希望这个你们都还记得,递归抛开不聊,迭代的思路是把这个二叉树扔到一个队列里面做循环,然后算出来高度。
记不清楚的同学可以返回去看看第 22 天的文章,求一个二叉树的最大深度。
这篇文章实际上使用的是一个自顶向下的遍历方案,我看了今天这道题的答案,发现还能自底向上(果然每个答案的思路都会非常的清奇,这就是每天背答案的价值)。
解题方案一:自顶向下递归
首先定义一个求子树高度的 height()
方法,有了这个方法以后,我们从根节点开始递归整个二叉树的左右子节点,并且判断左右子节点的差的绝对值是否小于 1 。
// 自顶向下递归
public boolean isBalanced(TreeNode root) {
if (root == null) return true;
else return Math.abs(height(root.left) - height(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);
}
public int height(TreeNode root) {
if (root == null) return 0;
else return Math.max(height(root.left), height(root.right)) + 1;
}
解题方案二:自底向上递归
上面的这种自顶向下的递归方案虽然可以求出最后的结果,但是我们在求某一个节点的高度的时候, height()
方法会被多次调用,无形之中增加了时间复杂度。
官方的题解中从而给出了一个很新奇的解法,从底向上递归。
在这种解法中,先递归的判断其左右子树是否平衡,再判断已当前节点为根的子树是否平衡,如果是平衡的,则返回其高度,如果不平衡,则返回 -1 。
如果有一个子树不平衡,那么整个子树必定不平衡,这种方案无需遍历所有的节点,只要遇到不平衡的子树直接返回,只有在最差的情况下会遍历二叉树中的所有节点,这时的时间复杂度是 O(n) 。
// 自底向上递归
public boolean isBalanced_1(TreeNode root) {
return height_1(root) >= 0;
}
public int height_1(TreeNode root) {
if (root == null) return 0;
int leftHeight = height_1(root.left);
int rightHeight = height_1(root.right);
if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {
return -1;
} else {
return Math.max(leftHeight, rightHeight) + 1;
}
}