题目
输入一棵二叉树,判断该二叉树是否是平衡二叉树。
解析
预备知识
平衡二叉树:它是一棵空树,或者它的左右子树的高度差不超过1,同时它的左右子树为一棵二叉树。而衡量树和平衡因子说的就是左右子树的高度差,可以为0,1,-1。如下图它就是一棵平衡二叉树:
通过定义我们就知道如何判断一棵二叉树是否是平衡二叉树了:
-
空树和只有root节点的树是平衡二叉树,
-
然后就是判断root的左右子树深度差是否大于1——
- 如果大于1则这棵树肯定不是平衡二叉树,
- 如果小于1再继续判断左右子树是否为平衡二叉树
-
如此递归。
常规思路:
代码:
public class Solution {
public boolean IsBalanced_Solution(TreeNode root) {
if(root == null || (root.left == null && root.right == null))
return true;
int left = TreeDepth(root.left);
int right = TreeDepth(root.right);
if(Math.abs(left - right) > 1)
return false;
return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
}
public int TreeDepth(TreeNode root) {
if(root == null)
return 0;
return Math.max(TreeDepth(root.left),TreeDepth(root.right))+1;
}
思路一虽然实现简单,但存在非常重要的缺陷。
就是在求节点的深度会重复遍历多个节点。比如上图中,我们求2节点的深度时,需要遍历2->4,而在求1的节点深度时,又要遍历1->2->4。
能不能在求节点的深度只需遍历一次节点,或者说我们在递归回溯时如何利用左右孩子的深度从而避免多次遍历。
我们这里就采用利用递归回溯时,上一次递归时得到的子树的高度来求出当前树结构的深度。
其实思路一TreeDepth也利用此思想,但是它确实单独的模块,没有与判断平衡二叉树结合在一起。
所以思路二主要是将思路一中的分开模块结合在一起。
利用一个全局变量表示平衡标志位——
在求树的深度时,对求得的左右子树的高度进行判断是否符合平衡二叉树的要求,若不满足,平衡标志位为false。
并且在求树的深度的开头部分会判断这个标志位,
若为false,则说明该树的某一部分不平衡,直接返回即可,
表明这个树不是平衡的。
代码:
public class Solution {
//后续遍历时,遍历到一个节点,其左右子树已经遍历 依次自底向上判断,每个节点只需要遍历一次
static boolean isBalance = true;
public static boolean IsBalanced_Solution(TreeNode root) {
if(root == null) {
return true;
}
isBalance = true;
caculateBalanceTree(root);
return isBalance;
}
private static int caculateBalanceTree(TreeNode node) {
if(node == null || !isBalance) {
return 0;
}
int left = caculateBalanceTree(node.left);
int right = caculateBalanceTree(node.right);
isBalance = Math.abs(left - right) < 2 ? true : false;
return Math.max(left, right) + 1;
}
}