LeetCode 110. 平衡二叉树思考分析

100 阅读4分钟

题目

给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过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 。

思路一:递归记录每个结点的高度+层序遍历检查高度差

不过这样的效率较低,毕竟遍历了两遍。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int getDepth(TreeNode* node)
    {
        if(node == NULL) return 0;
        int left=getDepth(node->left);
        int right=getDepth(node->right);
        node->val = max(left,right)+1;
        return max(left,right)+1;
    }
    bool isBalanced(TreeNode* root) {
        getDepth(root);
        queue<TreeNode*> que;
        if(root!=NULL) que.push(root);
        int num=0;
        while(!que.empty())
        {
            //该层结点元素个数 = 该层队列元素
            int size = que.size();
            //这里要使用固定大小的size,不能使用que.size(),因为在处理中que.size是不断变化的
            //将这层元素送入队列中并依次从队首向队尾将元素出队列,每个元素出队列的同时又将其不为空的子结点送入队列
            for(int i =0;i<size;i++)
            {
                TreeNode* node = que.front();
                //将队首元素送入该层结果
                que.pop();
                if(node->left && node->right)
                {
                    if(abs(node->left->val - node->right->val)>1)
                    {
                        return false;
                    }
                }
                if(node->left && !node->right)
                {
                    if(node->left->val>1)
                    {
                        return false;
                    }
                }
                if(!node->left && node->right)
                {
                    if(node->right->val>1)
                    {
                        return false;
                    }
                }
                //将左右孩子结点入队列,作为下一层的元素
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        return true;
    }
};

在这里插入图片描述

参考其他思路

概念辨析:
二叉树结点的深度:指从根结点到该结点的最长简单路径边的条数
二叉树结点的高度:指从该结点到叶结点的最长简单路径边的条数
leetcode中强调的深度和高度很明显是按照结点来计算。
深度是从上到下去查,所以需要前序遍历(中左右),而高度只能从下到上去查,所以只能使用后序遍历(左右中)。
根结点的最大深度就是这个根结点的高度。
递归三部曲分析:
1、确定递归参数和返回值
参数:传入的结点指针
返回值:返回传入结点为根结点的树的高度。
如果已经不是二叉平衡树了可以返回-1进行标记。

//-1 表示已经不是平衡二叉树了,否则返回值就是以该节点为更急诶·根结点的树的高度(最大深度)
int getDepth(TreeNode* node)

2、明确终止条件
遇到空结点终止,返回0

if(node ==NULL) return 0 ;

3、明确单层逻辑

1、如果左子树不是平衡二叉树,返回-1
2、如果右子树不是平衡二叉树,返回-1
3、如果左右子树的高度差大于1,返回-1
4、否则,返回结点高度

int leftDepth = getDepth(node->left);
if(leftDepth == -1) return -1;
int rightDepth= getDepth(node->right);
if(rightDepth== -1) return -1;
if(abs(leftDepth - rightDepth)>1) return -1;
else return 1+max(leftDepth,rightDepth);

4、完整递归代码

int getDepth(TreeNode* node)
{
	if(node ==NULL) return 0 ;
	int leftDepth = getDepth(node->left);
	if(leftDepth == -1) return -1;
	int rightDepth= getDepth(node->right);
	if(rightDepth== -1) return -1;
	if(abs(leftDepth - rightDepth)>1) return -1;
	else return 1+max(leftDepth,rightDepth);
}

5、举例分析
在这里插入图片描述
以左侧为例:
4:高度为 1
3:高度为 2
2:高度为3,它的左子树高度为2,右子树高度为0,高度差大于1,所以非平衡树。
下面是我写的错误的代码,原因是对平衡二叉树的理解出现了差错,是两个子树的高度差大于1。
而且考虑到出现一次非平衡状态就直接返回-1,一直返回到原结点,从而减少时间浪费。

错误代码:
int getDepth(TreeNode* node) { if(node == NULL) return 0; int left=getDepth(node->left); int right=getDepth(node->right); if(node->left && node->right) { if(abs(left-right)>1) { return -1; } } if(node->left && !node->right) { if(left>1) { return -1; } } if(!node->left && node->right) { if(right>1) { return -1; } } return max(left,right)+1; }
AC代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int getDepth(TreeNode* node)
    {
        if(node ==NULL) return 0 ;
        int leftDepth = getDepth(node->left);
        if(leftDepth == -1) return -1;
        int rightDepth= getDepth(node->right);
        if(rightDepth== -1) return -1;
        if(abs(leftDepth - rightDepth)>1) return -1;
        else return 1+max(leftDepth,rightDepth);
    }
    bool isBalanced(TreeNode* root) {
        if(getDepth(root)==-1) return false;
        return true;
    }
};

在这里插入图片描述

总结

了解了二叉树的深度与高度的差异,求深度适合用前序遍历,求高度适合用后序遍历。