剑指offer(41):判断二叉树是否为平衡二叉树(AVL树)

题目描述

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

分析

平衡二叉树(Balanced Binary Tree)又被称为AVL树,且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。

直接思路:由于可以方便地递归计算二叉树的深度(参见文章剑指offer(40):二叉树的深度)。按照AVL树的定义,顺序遍历二叉树的每一个节点,分别计算左右子树的深度,判断深度是否相差1;如果不是,直接返回false,否则递归判断该节点的左子节点和右子节点。但是该算法有一个问题,从上往下递归遍历计算每一个节点的深度时,有很多节点会发生重复遍历,越深层次的重复遍历次数越高,因此会影响性能。

代码:

public boolean IsBalanced_Solution(TreeNode root) {
        if(root == null)
            return true;

        int leftDepth = TreeDepth(root.left);
        int rightDepth = TreeDepth(root.right);
        int diffDepth = leftDepth - rightDepth;
        if(diffDepth < -1 || diffDepth > 1)
            return false;

        return IsBalanced_Solution(root.left) && IsBalanced_Solution(root.right);
    }

    public int TreeDepth(TreeNode root) {
        if(root == null)
            return 0;
        else 
            return max(TreeDepth(root.left), TreeDepth(root.right)) + 1;
    }

    public int max(int num1, int num2) {
        return (num1 > num2) ? num1 : num2;
    }

推荐解法

后序遍历,左右根,判断每个节点是否是平衡节点。当遍历到一个根节点时,先遍历该根节点的左右子树,计算左右子树的深度并通过传址的方式进行向上传递;如果该根节点是平衡节点,则向上遍历该节点的父亲节点,父亲节点的深度在之前传递的深度基础上加1即可,因此避免了深度计算中的节点重复遍历,提高了效率。

后序遍历适用于对二叉树进行“自底向上”的操作。

牛客AC:

package com.problem;

/** * 输入一棵二叉树,判断该二叉树是否是平衡二叉树。 * * key: 后续遍历的方法,避免重复遍历节点 * * * @author Administrator * */

public class BalancedBinaryTree {
    class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
        public TreeNode(int val) {
            this.val = val;
        }
    }

    public boolean IsBalanced_Solution(TreeNode root) {
        int[] depth = {0};
        return isBalancedTree(root, depth);
    }

    /** * * @param root 根节点 * @param depth 深度,数组传址参数,需要在函数调用后改变depth,参与运算 * 类似于c++中的引用参数 * @return */
    public boolean isBalancedTree(TreeNode root, int[] depth) {
        if(root == null) {
            depth[0] = 0;
            return true;
        }

        // 数组传址参数,用于传递函数调用后的数据,参与运算
        int[] leftDepth = {0};
        int[] rightDepth = {0};

        // 后续遍历,左右根,判断每个节点是否是平衡节点
        // 当遍历到一个根节点时,先遍历该根节点的左右子树,计算左右子树的深度并通过
        // 传址的方式进行向上传递;如果该根节点是平衡节点,则向上遍历该节点的父亲节点,
        // 父亲节点的深度在之前传递的深度基础上加1即可,
        // 因此避免了深度计算中的节点重复遍历,提高了效率
        if(isBalancedTree(root.left, leftDepth) && isBalancedTree(root.right, rightDepth)) {
            int diffDepth = leftDepth[0] - rightDepth[0];
            if(diffDepth >= - 1 && diffDepth <= 1) {
                int tmpDepth = (leftDepth[0] > rightDepth[0]) ? leftDepth[0] : rightDepth[0];
                depth[0] = 1 + tmpDepth;
                return true;
            }
        }
        return false;
    }
}

参考
1. 何海涛,剑指offer名企面试官精讲典型编程题(纪念版),电子工业出版社

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/u011080472/article/details/51264433
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞