算法通关村——轻松搞定二叉树高度和深度问题

算法通关村系列文章目录



前言

本系列文章是针对于鱼皮知识星球——编程导航中的算法通关村中的算法进行归纳和总结。 该篇文章讲解的是第八中的白银挑战和黄金挑战———二叉树的深度和高度问题

在这一期中,我们主要是来看一下二叉树的深度和高度的有关问题,并且在题目中,我们会大量使用递归的思想来处理问题,所以,本期也会再着重复习一下在二叉树问题中,递归的基本思路和构造方式的问题

反向后,节点原来连接的其他节点如何处理

经典的链表反转方法有头插法和直接反向法


一、最大深度问题

LeetCode 104:
给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数
在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:3

后面几道题我们都通过递归的思想来做

步骤:

  1. 对于每一个节点来说,由他开头的最大路径一定是,左子树和右子树中路径较大的那个路径+1.
  2. 如果对于一个节点,他的左节点和右节点都是null,那么他就是叶子节点,同时也是一个路径的终点,这时候我们只要返回1即可

按我们上述思路可以很轻松的写出代码

    public static int maxD(TreeNode root){
        if(root.left==null&&root.right==null){
            return 1;
        }
        int left=0;
        int right=0;
        if(root.left!=null){
            left= maxD(root.left) + 1;
        }
        if(root.right!=null){
            right=maxD(root.right)+1;
        }
        return Math.max(left,right);
    }

从这我们也可以管中窥豹,只要搞清递归每一次要做的事情,把终止条件想清后,对于一般的递归题目还是很容易的


二、判断平衡树

LeetCode 110:
给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1
在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:true

步骤:

  1. 对于每一个节点来说,先把left,right依次递归得到,左子树的高度和右子树的高度,如果其中任意一个返回-1,就说明,左子树或右子树已经不平衡了,那对于这个节点来说,自然也就不平衡了,直接返回-1就好了
  2. 如果都不是-1,那就进入比较,如果高度差<=1的话,那么符合要求,最后返回最大的那个再加个1,如果>1了,那就符合了,直接返回-1
  3. 如果遍历到叶子节点了,那就没法往后递归了,直接返回1即可。
    public static int recur(TreeNode root){

        if(root.left==null&&root.right==null){
            return 1;
        }
        int left=0;
        int right=0;
        if(root.left!=null)    left = recur(root.left);
        if(left==-1) return -1;
        if(root.right!=null)   right= recur(root.right);
        if(right==-1) return -1;
        return Math.abs(right-left)<=1?Math.max(left,right)+1:-1;
    }

转换为代码

main

三、最小深度

LeetCode 111:
给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点。
在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:2

这个最小深度,跟我们上面做的最大深度的思路都是差不多的,只是在初始化变量的时候,要设置成 Integer.MAX_VALUE,不能再设置为0了。

步骤:

  1. 对于每一个节点来说,以它开头的最短路径一定是,左子树和右子树中相较较小的那个路径+1即可。
  2. 当遍历到叶子节点,没有办法再往下遍历,就直接返回1即可

代码:

    public static int minDepth(TreeNode root){
        if(root==null) return 0;
        if(root.left==null&&root.right==null){
            return 1;
        }
        int left=Integer.MAX_VALUE,right=Integer.MAX_VALUE;
       if(root.left!=null)  left=minDepth(root.left);
       if(root.right!=null) right=minDepth(root.right);
       return Math.min(left,right)+1;
    }

四、N叉树的最大深度

LeetCode 559:
给定一个 N 叉树,找到其最大深度。

最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。

N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。
在这里插入图片描述

输入:root = [1,null,3,2,4,null,5,6]
输出:3

这里它只是把原来的二叉树换成了N叉树,其本质还是一样,只是原来只需要比较两个路径,这里需要需要比较N条路径,其他的都一样

步骤:

  1. 对于每个节点来说,以它开头的最大路径,就是它的N个字节点开头的路径中最大的那个路径+1即可
  2. 如果遍历的节点是叶子节点的话,说明没法再往下遍历了,直接返回1即可
    public static int maxDepth_N(NTreeNode root) {
        if(root==null) return 0;
        if(root.children==null){
            return 1;
        }
        int max=0;
        for (NTreeNode child : root.children) {
            max=Math.max(maxDepth_N(child),max);
        }
        return max+1;
    }

五、最近公共祖先问题

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

在这里插入图片描述

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。

这道题就比较难了,就是递归中,每一层该做的事情不好区分了。我们先来看,题目要求我们找到规定的两节点的最近公共祖先。通过分析题目,我们会发现,最近的公共祖先的情况有:

  1. 两个节点本身中的一个
  2. 两个节点前面第一个分叉的节点

那对于这道题,我们可以这样想

  1. 对于每一个节点来说,如果他自身就是目前节点中的某一个,说明他就找到了目标节点,也就不用再往下找了,直接返回该目标节点的值,说明,对于这个分支来说,他找到了正确的路径,并且最近的祖先是返回的值。
  2. 相反,如果遍历到最后仍然没有找到,那就直接返回null,代表这一分支没有目标元素,直接舍弃即可。
  3. 那么当左右节点都返回后,就该比较了,如果左侧为null,右侧为null,说明对于该节点来说,他的左子树和右子树都没有目标节点,直接返回null就好了
  4. 如果左侧为null,右侧不为null,那就返回右侧的元素
  5. 同理右侧为null,左侧不为null,那就返回左侧的元素
  6. 如果左侧和右侧都返回了,那该节点不就是最近的公共祖先了嘛,那就返回他本身

我们按照思路很容易就把代码顺下来了

    public static TreeNode lowestCommonAncestor(TreeNode node,TreeNode p, TreeNode q){
        //这个并不是一个将节点连起来的操作,只是去看一看该节点的左树和右树,有没有符合情况的,如果left是null。说明左树没有符合情况的,right也同理。
        //如果左边返回的不是努null,那就说明左侧有,并且返回的还要啥最近的节点。
        if(node==null||node.val==p.val||node.val==q.val) return node;
        TreeNode left = lowestCommonAncestor(node.left,p,q);
        TreeNode right = lowestCommonAncestor(node.right,  p,q);
        if(left==null&&right==null) return null;
        if(left==null) return right;
        if(right==null) return left;
        return node;
    }

总结

当你好好分析了上面的几道题后,会发现上面的那几道都是有相同的思路的,对于每一个节点,都是要分别去对左节点和右节点分别遍历,并对这两个结果进行比较处理,最后返回就好了。本节的题大家一定要好好分析,这些不仅是二叉树的基础问题,同样也是我们递归思路养成的很好的题目。

那本节的内容就到此结束。我是Mayphyr,从一点点到亿点点,我们下次再见

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值