二叉树的深度和高度问题-算法通关村

二叉树的深度和高度问题-算法通关村


1 最大深度问题

  • LeetCode104: 给定一个二叉树,找出其最大深度。

  • 二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
    说明:叶子节点是指没有子节点的节点。

  • 对于node(3),最大深度自然是左右子结点+1,左右子节点有的可能为空,只要有一个,树的最大高度就是1+1=2。然后再增加几个结点:

  • 很显然相对于node(20),最大深度自然是左右子结点+1,左右子节点有的可能为空,只要有一个,树的最大高度就是1+1=2,用代码表示就是:

  • int depth = 1 + max(leftDepth, rightDepth);
    而对于3,则是左右子树深度最大的那个然后再+1,具体谁更大,则不必关心。所以对于node(3)的判断逻辑就是:

  • int leftDepth = getDepth(node, left);//左
    int rightDepth = getDepth(node, right)//右
    int depth = 1 + max(leftDepth, rightDepth);//中
  • 那什么时候结束呢,这里仍然是root == null返回0就行了。至于入参,自然是要处理的子树的根节点root,而返回值则是当前root所在子树的最大高度。所以合在一起就是:

  •   public int maxDepth(TreeNode root){
              if(root == null){
                  return 0;
              }
              int leftDepth = maxDepth(root.left);
              int rightDepth = maxDepth(root.right);
              return Math.max(leftDepth, rightDepth) + 1;
          }
    
  • 上面代码先拿到左右子树的结果再计算Math.max(left, right)+ 1,这与后序遍历本质上一样的,因此可以看做后序遍历的拓展问题。
    我们继续分析这个题,如果确定树最大有几层是不是也就知道最大深度了?是的,直接套用层序遍历的代码就可以。

  •   public int maxDepth2(TreeNode root){
              if(root == null){
                  return 0;
              }
              Deque<TreeNode> queue = new ArrayDeque<>();
              queue.offer(root);
              int depth = 0;
              while(!queue.isEmpty()){
                  for(int i = 0; i < queue.size(); i++){
                      TreeNode temp = queue.poll();
                      if(temp.left != null){
                          queue.offer(temp.left);
                      }
                      if(temp.right != null){
                          queue.offer(temp.right);
                      }
                  }
                  depth++;
              }
              return depth;
          }
    

2 判断平衡二叉树

  • LeetCode110 判断平衡二叉树:给定一个二叉树,判断它是否是高度平衡的二叉树。本题中,一棵高度平衡二叉树定义为:一个二叉树**每个节点** 的左右两个子树的高度差的绝对值不超过1。
    这里的要求是二又树每个节点的左右两个子树的高度差的绝对值不超过1。先补充一个问题,高度和深度怎么区分呢?
    • 二又树节点的深度:指从根节点到该节点的最长简单路径边的条数。
    • 二又树节点的高度:指从该节点到叶子节点的最长简单路径边的条数。
    直接看图:

  • 关于根节点的深度究竟是1还是0,不同的地方有不一样的标准,leetcode的题目中都是以根节点深度是1,其他的就不管了。
    言归正传,我们仍然先看一个最简单的情况:

  • 很显然只有两层的时候一定是平衡的,因为对于node(3),左右孩子如果只有一个,那高度差就是1;如果左右子孩子都有或者都没有,则高度差为0。如果增加一层会怎么样呢?如下图:

  • 对于node(3),需要同时知道自己左右子树的最大高度差是否<2。

    • 当节点root 左 / 右子树的高度差<2,则返回节点 root 的左右子树中最大高度加1(max(left, right) + 1);参考上面的高度和深度的对比图思考一下,这里为什么是最大高度?
    • 当节点root 左/右子树的高度差 ≥2:则返回-1,代表 此子树不是平衡树。
      也就是:
  • int left = recur(root.left);
    int right = recur(root.right);
    return Math.abs(left-right) < 2 ? Math.max(left, right) + 1 : -1;
  • 这就是核心递归,假如子树已经不平衡了,则不需要再递归了直接返回就行,比如下面树中的结点4

  •   class BalancedTree{
          public boolean isBalanced(TreeNode root){
              return height(root) >= 0;
          }
          public int height(TreeNode root){
              if(root == null){
                  return 0;
              }
              int leftDepth = height(root.left);
              int rightDepth = height(root.right);
              if(leftDepth == -1 || rightDepth == -1 || Math.abs(leftDepth-rightDepth) > 1){
                  return -1;
              }else{
                  return Math.max(leftDepth, rightDepth) +1;
              }
          }
      }
    

3 最小深度

  • 既然有最大深度,那是否有最小深度呢?LeetCode111:给定一个二叉树,找出其最小深度。最小深度是**从根节点到最近叶子节点的**最短路径上的节点数量,例如下面的例子返回结果为 3 。说明:叶子节点是指没有子节点的节点。

  • 这里的关键问题是题目中说的:最小深度是从根节点到最近叶子节点的最短路径上的节点数量,也就是最小深度的一层必须要有叶子结点。

  • 这里的核心问题仍然是分析终止条件:

    • 如果左子树为空,右子树不为空,说明最小深度是1+右子树的深度。
    • 反之,右子树为空,左子树不为空,最小深度是1+左子树的深度。
    • 最后如果左右子树都不为空,返回左右子树深度最小值+1。
      代码如下:
  •   public int minDepth(TreeNode root){
              if(root == null){
                  return 0;
              }
              //说明root是一个叶子节点,其最小深度为1
              if(root.left == null && root.right == null){
                  return 1;
              }
              //为了确保在比较时,任何实际的深度值都会比这个初始值小。
              int min_depth = Integer.MAX_VALUE;
              if(root.left != null){
                  min_depth = Math.min(minDepth(root.left), min_depth);
              }
              if(root.right != null){
                  min_depth = Math.min(minDepth(root.right), min_depth);
              }
              return min_depth + 1;
          }
      
    
  • 除了递归方式,我们也可使用层次遍历,只要遍历时,第一次遇到叶子就直接返回其所在的层次即可。

  •   public int minDepth2(TreeNode root){
              if(root == null){
                  return 0;
              }
              Deque<TreeNode> queue = new ArrayDeque<>();
              queue.offer(root);
              int minDepth = 0;
              while(!queue.isEmpty()){
                  //将minDepth增加1,表示当前遍历的深度增加了一层
                  minDepth++;
                  for(int i = 0; i < queue.size(); i++){
                      TreeNode temp = queue.poll();
                      if(temp.left == null && temp.right == null){
                          return minDepth;
                      }
                      if(temp.left != null){
                          queue.offer(temp.left);
                      }
                      if(temp.right != null){
                          queue.offer(temp.right);
                      }
                  }
              }
              return 0;
          }
    

4 N叉树的最大深度

  • 如果将二叉树换成N叉树又该怎么做呢?

  • LeetCode559.给定一个 N 叉树,找到其最大深度。最大深度是指从根节点到最远叶子节点的最长路径上的节点总数。
    N 叉树输入按层序遍历序列化表示,每组子节点由空值分隔(请参见示例)。

  • 示例1:
    输入:root = [1, null, 3, 2, 4, null, 5, 6]
    输出:3
    示例2:
    输入:root = [ 1, null, 2, 3, 4, 5, null, null, 6, 7, null, 8, null, 9, 10, null, null, 11, null, 12, null, 13, null, null, 14 ]
    输出:5
  • 这道题就是将二叉树换成了N叉树,不同点就在于N叉树节点比较多,我们使用list,遍历时用for即可。

  • N叉树的定义:

  •   public class Node {
          public int val;
          public List<Node> children;
      
          public Node() {
          }
      
          public Node(int val) {
              this.val = val;
          }
      
          public Node(int val, List<Node> children) {
              this.val = val;
              this.children = children;
          }
      }
    
  •   public int maxDepthNTree(Node root){
              if(root == null){
                  return 0;
              }else if(root.children.isEmpty()){
                  //当前节点是一个叶子节点,其最大深度为1,直接返回1。
                  return 1;
              }else{
                  List<Integer> heights = new ArrayList<>();
                  for (Node child : root.children) {
                      heights.add(maxDepthNTree(child));
                  }
                  return Collections.max(heights) + 1;
              }
          }
    
    
    
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/501491.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

el-select的错误提示不生效、el-select验证失灵、el-select的blur规则失灵

发现问题 在使用el-select进行表单验证的时候&#xff0c;发现点击下拉列表没选的情况下&#xff0c;他不会提示没有选择选项的信息&#xff0c;我设置了rule如下 <!--el-select--><el-form-item label"等级" prop"level"><el-select v-m…

UE4_碰撞_使用蓝图控制物体移动时如何让被阻挡

当我们这样设置蓝图时&#xff1a; 运行效果&#xff1a; 利用蓝图更改一个物体的位置&#xff0c;发现本来两个应该相互阻挡的物体被穿过去了。为了不让相互阻挡的物体被穿过去&#xff0c;我们需要设置好蓝图节点的参数Sweep。 勾选之后 墙的蓝图我们这样设置&#xff1a; 运…

【Spring】SpringMvc项目当中,页面删除最后一条数据,页面不跳转并且数据为空。

期待您的关注 在之前学习SpringMvc的时候遇到过这样一个BUG&#xff0c;当我在一个页面删除该页面的最后一条数据的时候&#xff0c;一旦我删除成功&#xff0c;那么这个页面不会进行跳转&#xff0c;而是还停留在这个本不应该存在的页面&#xff0c;而且数据什么都没有。如下…

【JavaWeb】Day27.Web入门——Tomcat介绍

目录 WEB服务器-Tomcat 一.服务器概述 二.Web服务器 三.Tomcat- 基本使用 1.下载 2.安装与卸载 3.启动与关闭 4.常见问题 四.Tomcat- 入门程序 WEB服务器-Tomcat 一.服务器概述 服务器硬件&#xff1a;指的也是计算机&#xff0c;只不过服务器要比我们日常使用的计算…

Typora for Mac/Win:让Markdown编辑更高效,创作更自由

在数字化时代&#xff0c;文本编辑已成为我们日常生活与工作中的重要环节。Markdown作为一种轻量级标记语言&#xff0c;以其简洁、易读、易写的特性&#xff0c;受到了广大用户的喜爱。而Typora&#xff0c;作为一款专为Markdown设计的文本编辑器&#xff0c;更是让Markdown编…

DBeaver,一款实用的开源数据库管理软件

说起开源软件&#xff0c;其实大部分的体验和服务都是没有商业软件好的&#xff0c;毕竟养团队不是靠鼓励和奉献&#xff0c;咱们选择开源软件的主要原因还是免费&#xff0c;免费&#xff0c;免费。 由于公司限制安装商业软件&#xff0c;咱只能挑开源的替代&#xff0c;其中…

计算机专业在找工作时的注意事项

目录 说在前面关于我一些忠告关于简历关于银行写在最后 说在前面 满满的求生欲。我不是什么大佬&#xff0c;更没有能力教大家什么。只是看到有不少学弟学妹&#xff0c;还在为找一份工作焦头烂额&#xff0c;却没有努力的方向。所以这里斗胆给计算机相关专业的学弟学妹们的一…

如何在 Linux 中查找命令的执行时间

在 Linux 操作系统中&#xff0c;查找命令的执行时间对于优化系统性能、调试程序以及评估脚本效率至关重要。本文将介绍几种方法来准确地测量命令的执行时间。 使用时间命令 时间命令&#xff08;time&#xff09;是一个内置的 shell 命令&#xff0c;用于测量其他命令或程序的…

【日常记录】【JS】getBoundingClientRect 获取元素位置和大小

文章目录 1、介绍2、getBoundingClientRect3、参考链接 1、介绍 getBoundingClientRect() 是一个用于获取元素位置和大小的方法。它返回一个 DOMRect对象&#xff0c;其提供了元素的大小及其相对于视口的位置&#xff0c; 2、getBoundingClientRect 参数&#xff1a;这个方法…

设计模式之代理模式精讲

代理模式&#xff08;Proxy Pattern&#xff09;也叫委托模式&#xff0c;是一个使用率非常高的模式&#xff0c;比如我们在Spring中经常使用的AOP&#xff08;面向切面编程&#xff09;。 概念&#xff1a;为其他对象提供一种代理以控制对这个对象的访问。 代理类和实际的主题…

二、Java语法基础

1、Java语言的关键字、标识符及命名规范 1)java关键字 2)标识符 3)JAVA中的命名规范 包名的命名规范:域名.公司名称.项目名称.模块名称 类的命名规范:首字母大写,第二个单词的首字母大写,以此类推。 2、进制间的转换(二进制、十进制) 1)十进制->二进制 采用…

PHP 跳转搜索(Jump Search)

与二分搜索一样&#xff0c;跳转搜索是一种针对排序数组的搜索算法。基本思想是通过按固定步骤向前跳跃或跳过某些元素来代替搜索所有元素来检查更少的元素&#xff08;比线性搜索&#xff09;。例如&#xff0c;假设我们有一个大小为 n 的数组 arr[] 和一个大小为 m 的块&…

基于Hive大数据分析springboot为后端以及vue为前端的的民宿系

标题基于Hive大数据分析springboot为后端以及vue为前端的的民宿系 本文介绍了如何利用Hive进行大数据分析,并结合Spring Boot和Vue构建了一个民宿管理系统。该民民宿管理系统包含用户和管理员登陆注册的功能,发布下架酒店信息,模糊搜索,酒店详情信息展示,收藏以及对收藏的…

宝塔面板与1Panel的详细对比分析

在当今的服务器管理领域&#xff0c;宝塔面板和1Panel都是备受欢迎的管理工具。它们各自具有独特的特点和优势&#xff0c;同时也存在一些局限性。本文将从多个维度对比这两款产品&#xff0c;帮助用户根据自身需求做出更合适的选择。 宝塔面板 优点 易用性&#xff1a;宝塔…

vue的创建、启动以及目录结构详解

vue的创建、启动以及目录结构详解目录 一. vue项目的创建 二. vue的目录结构 三. src的目录结构 四. vue项目的启动 4.1 方法1 4.2 方法2 一. vue项目的创建 创建一个工程化的Vue项目&#xff0c;执行命令&#xff1a;npm init vuelatest 注意&#xff1a;如果你在这个目…

国内如何购买midjourney?midjourney购买教程?midjourney注册方式?

1. Midjourney介绍 Midjourney 是一款备受欢迎的人工智能生成图像工具&#xff0c;它可以通过输入文字描述&#xff0c;自动生成精美的图像。与许多其他图像生成工具不同&#xff0c;Midjourney 不需要安装任何软件&#xff0c;也不受个人电脑性能的限制&#xff0c;因为它运行…

FANUC机器人故障诊断—报警代码(一)

一、SRVO-050碰撞检测报警 [原因]检测出碰撞 [对策] 1.确认机器人是否碰撞。 2.确认是否正确进行了负载设定。 3.确认是否有过载、过度的加速度附加指令。 4.在长期停用后启动&#xff0c;或者外部气温较低时发生该报警。启动后&#xff0c;先短时间内低速运转设备&#…

wordpress插件,免费的wordpress插件

WordPress作为世界上最受欢迎的内容管理系统之一&#xff0c;拥有庞大的插件生态系统&#xff0c;为用户提供了丰富的功能扩展。在内容创作和SEO优化方面&#xff0c;有一类特殊的插件是自动生成原创文章并自动发布到WordPress站点的工具。这些插件能够帮助用户节省时间和精力&…

图片怎么调整尺寸?图片宽度和高度怎么设置

平时在使用图片的时候&#xff0c;最常处理的就是图片尺寸问题&#xff0c;为了能让图片适用于更多的场景&#xff0c;那么怎么修改图片尺寸呢&#xff1f;试试本文介绍的几个关于图片改大小的方法吧&#xff0c;有需要图片大小转换的继续往下看。 压缩图网站&#xff0c;点击“…

【数据结构与算法】递归和逆置

线性数据结构的遍历 let arr [1,2,3,4]// 数组的基本遍历 function traverse(arr) {if (arr null) returnfor (let i 0; i < arr.length; i) {console.log(arr[i])} } traverse(arr)function Node(value) {this.value valuethis.null null }let node1 new Node(1) le…