剑指 Offer 55 - II. 平衡二叉树 题目描述:
给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
题目来源:力扣(LeetCode) 链接:https://leetcode.cn/problems/balanced-binary-tree
首先需要明确的一点是平衡二叉树的定义:树里面每个节点的左右子树的高度差不大于1 碰到这道题我们大多数情况下首先想到的必然是从递归入手。那么对于这个问题如何递归呢?前面有道题是求二叉树的最大深度的,这两者之间的递归思路其实有着很大的相似性,因为我们要确定节点的平衡也是要通过求解每个节点的左右子树的高度来入手的,这里我们需要区分一下树的节点的深度和高度。深度一般是从上到下,而高度是从下到上。
1.自顶向下递归(O(N),O(N))——类似于先序遍历
下面我们先介绍以下最容易想到的递归,我们根据题设条件先实现一个求每个节点的高度的函数getHeight,其实现如下,看起来与前面求解最大深度的递归方法十分类似,不过此时的高度从上到下递减。
int getHeight(TreeNode * root){
if(root == nullptr) return 0;
else return max(getHeight(root->left),getHeight(root->right))+1;
}
既然有了求解高度的功能实现,那么我们利用他来进行平衡的判断,我们知道成为一个平衡树需要满足两个条件
- 左右子树高度差不大于1
- 左右子树也是平衡树
根据这两个条件我们就可以写出如下递归逻辑的代码,我们可以看到递归的终止条件是节点为空,单层逻辑是判断上述的条件1和2,其中的2也就是我们实现的递归过程。这个递归判断是从判断根节点的平衡依次递到下面的子节点的平衡,然后再归于根节点。这就是一个自顶向下的过程,但是由于对于每个节点都要执行多次高度计算,导致了一些计算冗余,其时间复杂度达到了O(N2)
bool isBalanced(TreeNode* root) {
if(root == nullptr) return true;
else {
return abs(getHeight(root->left)-getHeight(root->right)) <= 1 && isBalanced(root->left) &&isBalanced(root->right);
}
}
2.自底向上递归((O(N2),O(N))——类似于后序遍历
上面的递归过程中多次求解了高度,导致了极大的计算冗余,是否可以想办法进行消除呢?我们分析一下其递归过程。每次判断节点是否是平衡的时候,需要先计算左右子树高度差,再进行左右子树是否是平衡树的判断,这相当于一个先序遍历的逻辑(先处理根节点再处理子节点)。因为每次处理一个节点都需要处理其下面的所有节点这就造成了冗余,那么如果我们从下到上处理节点会怎样呢?是否会消除这些重复的计算。
基于这一分析我们转变递归逻辑为后序遍历(先处理子节点,再处理根节点)。基于题意,两个判断条件不会改变。所以我们的递归单层逻辑还是判断左右子树高度差以及左右子树是否是平衡树。但是由于此时是自底向上的逻辑,所以每次我们处理到一个节点的时候其左右子树是否是平衡树已经被标记出,不用再冗余计算。所以我们实现的新的辅助函数如下。
注意其中的-1正是我们用来消除冗余的工具。当一个节点的高度标记为-1就表示这个节点不是一个平衡节点,其上方的节点则也不可能是平衡节点。否则getHeight 求的值就是节点本身的高度。我们可以得出,只要一个节点的getHeight 返回值不是-1,那么这个节点就是一个平衡节点。
int getHeight(TreeNode * root){
if(root == nullptr) return 0;
int leftHeight = getHeight(root->left);
if(leftHeight == -1) return -1;
int rightHeight = getHeight(root->right);
if(rightHeight == -1) return -1;
if(abs(leftHeight - rightHeight) > 1) return -1;
else return leftHeight > rightHeight ? leftHeight+1:rightHeight+1;
}
然后我们可以写出平衡树判断代码如下
bool isBalanced(TreeNode* root) {
return getHeight(root) > -1;
}
最后附上总体代码
class Solution {
public:
int getHeight(TreeNode * root){
if(root == nullptr) return 0;
int leftHeight = getHeight(root->left);
if(leftHeight == -1) return -1;
int rightHeight = getHeight(root->right);
if(rightHeight == -1) return -1;
if(abs(leftHeight - rightHeight) > 1) return -1;
else return leftHeight > rightHeight ? leftHeight+1:rightHeight+1;
}
bool isBalanced(TreeNode* root) {
return getHeight(root) > -1;
}
};
class Solution {
public:
int getHeight(TreeNode * root){
if(root == nullptr) return 0;
else return max(getHeight(root->left),getHeight(root->right))+1;
}
bool isBalanced(TreeNode* root) {
if(root == nullptr) return true;
else {
return abs(getHeight(root->left)-getHeight(root->right)) <= 1 && isBalanced(root->left) &&isBalanced(root->right);
}
}
};
|