剑指 Offer 55 - II. 平衡二叉树

剑指 Offer 55 - II. 平衡二叉树

我们注意到题目要求我们验证所有的节点是否平衡,所以需要遍历到每一个节点,这里使用前序遍历的方式来遍历到每一个节点。
并且,对于每一个节点,需要满足的条件是左右子树高度差不超过1且左右子树均是平衡的。
所以可以写出如下代码:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        return check(root);
    }

    // 检测某个节点是否是平衡的
    private boolean check(TreeNode root) {
        if(root == null) {
            return true;
        }
        var lDepth = getDepth(root.left);
        var rDepth = getDepth(root.right);
        return Math.abs(lDepth - rDepth) <= 1 && check(root.left) && check(root.right);
    }

    // 得到某个节点的深度
    private int getDepth(TreeNode root) {
        if(root == null) {
            return 0;
        }
        return 1 + Math.max(getDepth(root.left), getDepth(root.right));
    }
}

这个方法虽然好,但是可以发现有着许多重复计算在求depth时,getDepth函数对于许多节点有重复计算。
时间复杂度为\(O(nlogn)\),最差可能有n层,每一层的复杂度为\(O(logn)\)
接下来就是考虑后序遍历,后序遍历是自底向上,可以避免一些重复计算,而前序遍历是自顶向下,中间会有很多重复计算。
后序遍历则是,对于每一个节点,我们判断其左右子树是否平衡,如果平衡,继续返回这个节点的高度,否则返回一个退出的flag值,这里设置成-1。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isBalanced(TreeNode root) {
        return check(root) != -1;
    }
    // 检测node为根的子树是否平衡,平衡返回node的高度,不平衡返回-1
    private int check(TreeNode node) {
        if(node == null) {
            return 0;
        }
        int leftHeight = check(node.left);
        if(leftHeight == -1) {
            return -1;
        }
        int rightHeight = check(node.right);
        if(rightHeight == -1) {
            return -1;
        }
        if(Math.abs(leftHeight - rightHeight) <= 1) {
            return 1 + Math.max(leftHeight, rightHeight);
        } else {
            return -1;
        }
    }
}
posted @ 2022-02-01 17:03  NullPointer_C  阅读(31)  评论(0)    收藏  举报