1、二叉树的最大高度
- 分析:二叉树的高度为根节点到最远叶子节点的最长路径上的节点数。
- 思路:比较根结点的左右子树的最大高度 + 1(到根结点的高度);递到叶子结点那一层把高度依次返回给双亲结点,直到根根结点。
递推关系:而每一个结点的左子树高度都等于下一个结点的左子树高度+1(右子树那一路递归同理)
递归出口:递到最左子树为null
public int maxDepth(TreeNode root) {
if(root == null) {
return 0;
}
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return 1+Math.max(left,right);
}
2、判断一棵二叉树是否为平衡二叉树
平衡二叉树:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1
- 分析:
1、分别求出每个结点的左右子树的高度(如 1)
2、判断所有结点的左右子树高度差是否满足平衡条件,递归问题。
递推关系:遍历到每一个结点,求每一个结点的左右子树是否平衡
终止条件:遍历到结点为 null
- 思路:
1、求出当前结点的左右子树的高度
int leftHeight = getHeight(root.left)
int rightHeight = getHeight(root.right)
2、判断当前结点的左右子树的绝对值
Math.abs(leftHeight,rightHeight)>2 return false
Math.abs(leftHeight,rightHeight)<2 判断当前结点左右子树是否平衡(左右的高度差)
源代码:
public boolean isBalanced(TreeNode root) {
if(root == null) {
return true;
}
int leftHeight = getHeight(root.left);
int rightHeight = getHeight(root.right);
if(Math.abs(rightHeight - leftHeight) > 1) {
return false;
}
return isBalanced(root.left) && isBalanced(root.right);
}
private int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
return Math.max(getHeight(root.left),getHeight(root.right))+1;
}
这里存在一个效率问题,在判断根结点的时候,左右子树上每一个结点的高度已经求解过,当再求子树是否平衡的时候还需要再求一遍子树每个结点是否平衡
N个结点最坏时间复杂度就是 O(n^2)
优化:在求解当前结点的高度时,一定会递下去求子树高度,既然每次求当前结点高度都会求到子树的高度,那么有没有办法在求当前结点的时候把子树的平衡性直接判断。
思路:
- 通过一个参数将高度的判断结果带出来
- 判断子树平衡性,发现有一例 左/右子树高度差 > 1 的情况时,代表此树不是平衡树,返回-1;
- 在递的过程求当前结点的高度时,归的时候就会把当前结点以下所有结点情况判断了
- 一旦发现不是平衡树时,后面高度计算都无意义了,一路直接返回-1,避免后续再计算。
最差情况是对树做一遍完整DFS,时间复杂度为 O(N)
递归过程中:
终止条件:当DFS越过叶子节点时,返回高度0;
返回值:从底至顶,返回以每个节点root为根节点的子树最大高度 max(left,right) + 1);
public boolean isBalanced(TreeNode root) {
return getHeight(root) != -1;
}
private int getHeight(TreeNode root) {
if (root == null) {
return 0;
}
int leftHeight = getHeight(root.left);
if(leftHeight == -1) {
return -1;
}
int rightHeight = getHeight(root.right);
if(rightHeight == -1) {
return -1;
}
return Math.abs(leftHeight - rightHeight) < 2 ?
Math.max(leftHeight, rightHeight) + 1 : -1;
}