算法通关村第八关——树经典算法白银挑战笔记(树深度)

树深度作为树最经常的考察的算法,值得引起我们的关注!而树深度问题往往与递归密切相关,相信再温习完《第八关青铜挑战笔记》后,树类型的递归问题已经可以迎刃而解,那么继续趁热打铁,一举拿下有关“树深度”问题及其变式应用!

1.树最大深度

方法一:递归

递归出口:树为空,树高度为0

递归逻辑:树的最大高度问题,就是求左右子树的最大高度+1

厘清逻辑,直接上代码!

    public static int myMaxDepth_1(TreeNode root) {
        if(root == null) return 0;
        int leftDepth = myMaxDepth_1(root.left);
        int rightDepth = myMaxDepth_1(root.right);
        return Math.max(leftDepth, rightDepth) + 1;
    }

方法二:层序遍历(模板)

逻辑:每遍历一层,树深度就加一层。

厘清逻辑,直接上代码!

    public static int myMaxDepth_2(TreeNode root) {
        if(root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int size = 0;
        int depth = 0;
        while(!queue.isEmpty()){
            size = queue.size();
            for (int i = 0; i < size; i++) {
                TreeNode t = queue.poll();
                if(t.left != null) queue.offer(t.left);
                if(t.right != null) queue.offer(t.right);
            }
            depth++;
        }
        return depth;
    }

2.判断平衡树

什么是平衡树?左子树和右子树的高度差不超过1(左右子树是指树全部左右子树)。

那么问题就在于,求解左子树高度和右子树高度,然后进行判断。

当左子树高度和右子树的高度差大于1,那么这个树不是平衡树返回-1;当左右子树高度差小于2,该树为平衡树,返回树高度为:左右子树最大高度+1;当树为空,则返回0。

递归出口:当树为空,则返回0;当左子树不平衡,返回-1;当右子树不平衡,返回-1

递归逻辑:先判断左右子树是否平衡,当左右子树平衡且左右子树高度差小于2,该树为平衡树,返回树高度为:左右子树最大高度+1,否则不是平衡树,返回-1。

厘清思路,直接上代码!

    public static boolean myIsBalanced_1(TreeNode root) {
        return myRecur(root) != -1;
    }    

    public static int myRecur(TreeNode root) {
        if(root == null) return 0;
        int left = myRecur(root.left);
        if(left == -1) return -1;
        int right = myRecur(root.right);
        if(right == -1) return -1;
        return Math.abs(left- right) < 2 ? Math.max(left, right) + 1 : -1;
    }

3.最小深度

根据树的最大深度,题目变式出了最小深度,该怎么处理?

方式一:层序遍历(模板)

遍历树的每一层,当该层第一次出现叶子节点的时候,该层深度就是树最小深度!厘清逻辑,直接上代码!

    public static int myMinDepth_2(TreeNode root) {
        if(root == null) return 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        int size = 0;
        int depth = 0;
        while(!queue.isEmpty()){
            size = queue.size();
            depth++;
            for (int i = 0; i < size; i++) {
                TreeNode t = queue.poll();
                if(t.left != null) queue.offer(t.left);
                if(t.right != null) queue.offer(t.right);
                if(t.left == null && t.right == null) return depth;
            }
        }
        return depth;
    }

方式二:递归

递归出口:当树为空,树最小高度为0;

递归逻辑:当树节点的左孩子为空,树高度就是右子树高度+1;当树节点的右孩子为空,书高度就是左子树高度+1;当树节点左右孩子都不为空,树最小高度,就是左右子树的最小高度+1;(黑色加粗部分就是最小树高和最大树高问题的区别所在)

厘清逻辑,直接上代码!

    public static int myMinDepth_1(TreeNode root) {
        if(root == null) return 0;
        if(root.left == null) return myMinDepth_1(root.right) + 1;
        if(root.right == null) return myMinDepth_1(root.left) + 1;
        return Math.min(myMinDepth_1(root.left), myMinDepth_1(root.right)) + 1;
    }

4.N叉树最大深度

N叉树的最大高度我们当然会按照两种方式进行思考,递归和层序遍历!

层序遍历,方法很简单,只需要统计遍历的几层即可!

递归方法,只需要记录当前节点的所有子树树高,然后选择最大的树高+1,就是当前N叉树最大高度。

递归出口:树为空,返回树高度为0;

递归逻辑:记录当前节点的所有子树树高,然后选择最大的树高+1

先按照这个思路写出代码!

    public static int myMaxDepth_N(NTreeNode root) {
        if(root == null) return 0;
        ArrayList<Integer> listDepth = new ArrayList<>();
        for (NTreeNode child : root.children) {
            listDepth.add(myMaxDepth_N(child));
        }
        return Collections.max(listDepth) + 1;
    }

上面的代码有什么问题吗?当然有了!再for中child选择必须保证root.children不为空,而root.children为空意味着该节点为叶子节点,应该返回高度为1。于是,我们对上面代码进行修改:

    public static int myMaxDepth_N(NTreeNode root) {
        if(root == null) return 0;
        if(root.children == null) return 1;
        ArrayList<Integer> listDepth = new ArrayList<>();
        for (NTreeNode child : root.children) {
            listDepth.add(myMaxDepth_N(child));
        }
        return Collections.max(listDepth) + 1;
    }

这下没什么问题了吧,哈哈!别高兴太早,还有坑没填!坑在哪里?Collection.max()函数!试想,当root.children不为空但是root.children中没有任何元素,即是一个空列表的情况下,listDepth也必然是一个空列表!那么调用Collection.max()函数就会抛出异常!

怎么解决?增加条件呗!root.childern.isEmpty()这也表明没有孩子节点,为叶子节点,同时应该返回高度为1,于是继续修改代码!

    public static int myMaxDepth_N(NTreeNode root) {
        if(root == null) return 0;
        if(root.children == null || root.children.isEmpty()) return 1;
        ArrayList<Integer> listDepth = new ArrayList<>();
        for (NTreeNode child : root.children) {
            listDepth.add(myMaxDepth_N(child));
        }
        return Collections.max(listDepth) + 1;
    }

至此,N叉树的最大高度问题已经顺利解决了,我猜到这里聪明的你,已经能给自己出题了吧!

来吧!N叉树最小高度问题!怎么解决?答:两个思路,递归和层序遍历。

层序遍历,找到第一个叶子节点层,输出该层高度即可。

递归:递归出口:当树为空,树最小高度为0;当树节点的孩子都为空,该节点是叶子节点,树高度1;递归逻辑:当树节点有孩子节点的时候,树最小高度,就是孩子子树的最小高度+1;

代码留给你吧!加油!

OK,《算法通关村第八关——树经典算法白银挑战笔记》结束,喜欢的朋友三联加关注!关注鱼市带给你不一样的算法小感悟!(幻听)

再次,感谢鱼骨头教官的学习路线!鱼皮的宣传!小y的陪伴!ok,拜拜,第八关第三幕见!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值