二叉树题目:具有所有最深结点的最小子树

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:具有所有最深结点的最小子树

出处:865. 具有所有最深结点的最小子树

难度

5 级

题目描述

要求

给定二叉树的根结点 root \texttt{root} root,每个结点的深度是该结点到根的最短距离

返回包含原始树中所有最深结点的最小子树。

如果一个结点在整个树的所有结点中具有最大的深度,则该结点是最深的

一个结点的子树是该结点加上它的所有后代的集合。

示例

示例 1:

示例 1

输入: root = [3,5,1,6,2,0,8,null,null,7,4] \texttt{root = [3,5,1,6,2,0,8,null,null,7,4]} root = [3,5,1,6,2,0,8,null,null,7,4]
输出: [2,7,4] \texttt{[2,7,4]} [2,7,4]
解释:
我们返回值为 2 \texttt{2} 2 的结点,在图中用黄色标记。
在图中用蓝色标记的是树的最深的结点。
注意,结点 5 \texttt{5} 5 3 \texttt{3} 3 2 \texttt{2} 2 包含树中最深的结点,但结点 2 \texttt{2} 2 的子树最小,因此我们返回它。

示例 2:

输入: root = [1] \texttt{root = [1]} root = [1]
输出: [1] \texttt{[1]} [1]
解释:根结点是树中最深的结点。

示例 3:

输入: root = [0,1,3,null,2] \texttt{root = [0,1,3,null,2]} root = [0,1,3,null,2]
输出: [2] \texttt{[2]} [2]
解释:树中最深的结点为 2 \texttt{2} 2,有效子树为结点 2 \texttt{2} 2 1 \texttt{1} 1 0 \texttt{0} 0 的子树,但结点 2 \texttt{2} 2 的子树最小。

数据范围

  • 树中结点数目在范围 [1, 500] \texttt{[1, 500]} [1, 500]
  • 0 ≤ Node.val ≤ 500 \texttt{0} \le \texttt{Node.val} \le \texttt{500} 0Node.val500
  • 树中的所有值各不相同

解法一

思路和算法

由于所有最深结点的深度相同,因此对于包含所有最深结点的子树,每个最深结点到子树根结点的距离相同。只要定位到所有最深结点,即可找到包含所有最深结点的最小子树的根结点。

为了定位到所有最深结点,可以使用层序遍历。从根结点开始依次遍历每一层的结点,在层序遍历的过程中需要区分不同结点所在的层,确保每一轮访问的结点为同一层的全部结点。遍历每一层结点之前首先得到当前层的结点数,即可确保每一轮访问的结点为同一层的全部结点。层序遍历访问的最后一层结点即为所有最深结点。

定位到所有最深结点之后,从最深结点向根结点移动,即每次从当前结点移动到父结点。由于每个最深结点到子树根结点的距离相同,因此每个最深结点将同时移动到包含所有最深结点的最小子树的根结点。使用哈希集合存储每次移动之后的结点集合,每次移动之后,结点数量一定不变或减少,当只剩下一个结点时,该结点即为包含所有最深结点的最小子树的根结点。

代码

class Solution {public TreeNode subtreeWithAllDeepest(TreeNode root) {Map<TreeNode, TreeNode> parentMap = new HashMap<TreeNode, TreeNode>();List<TreeNode> deepest = new ArrayList<TreeNode>();Queue<TreeNode> queue = new ArrayDeque<TreeNode>();queue.offer(root);while (!queue.isEmpty()) {deepest.clear();int size = queue.size();for (int i = 0; i < size; i++) {TreeNode node = queue.poll();deepest.add(node);TreeNode left = node.left, right = node.right;if (left != null) {parentMap.put(left, node);queue.offer(left);}if (right != null) {parentMap.put(right, node);queue.offer(right);}}}Set<TreeNode> nodes = new HashSet<TreeNode>(deepest);while (nodes.size() > 1) {Set<TreeNode> parents = new HashSet<TreeNode>();for (TreeNode node : nodes) {parents.add(parentMap.get(node));}nodes = parents;}return nodes.iterator().next();}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。层序遍历访问每个结点一次,需要 O ( n ) O(n) O(n) 的时间,从所有最深结点移动到包含所有最深结点的最小子树的根结点的时间不超过 O ( n ) O(n) O(n),因此总时间复杂度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是队列空间和哈希集合,队列内元素个数不超过 n n n,哈希集合内元素个数不超过 n n n

解法二

思路和算法

对于二叉树中的每个结点,考虑其左子树和右子树的深度。如果左子树和右子树的深度相同,则左子树和右子树中都有最深结点,当前结点就是包含所有最深结点的最小子树的根结点;如果左子树和右子树的深度不同,则所有最深结点一定在深度较大的子树中,需要在深度较大的子树中寻找包含所有最深结点的最小子树的根结点。因此,寻找包含所有最深结点的最小子树的根结点,等价于寻找左子树和右子树的深度相同的结点,以下将该结点称为「目标结点」。

从根结点开始深度优先搜索,计算每个子树的深度,并寻找目标结点。定义空树的深度为 0 0 0,当子树非空时,子树的深度为左子树的深度和右子树的深度中的最大值加 1 1 1

寻找目标结点的具体做法如下。

  1. 如果当前结点的左子树的深度和右子树的深度相同,则当前结点即为目标结点,当前子树的深度为左子树的深度加 1 1 1

  2. 否则,在深度较大的子树中寻找目标结点,当前子树的深度为深度较大的子树的深度加 1 1 1

上述过程是一个递归的过程,递归的终止条件是当前结点为空或者当前结点的左子树的深度和右子树的深度相同,其余情况则调用递归。

对于每个结点,首先访问其子结点寻找目标结点和计算子树高度,然后根据访问子结点的结果得到当前结点的结果。计算结果的顺序是先计算子结点的结果,后计算当前结点的结果,该顺序实质是后序遍历。由于在计算每个结点的结果时,该结点的子结点的结果已知,该结点的结果由子结点的结果决定,因此可以确保结果正确。

代码

class Solution {class NodeDepth {private TreeNode node;private int depth;public NodeDepth(TreeNode node, int depth) {this.node = node;this.depth = depth;}public TreeNode getNode() {return node;}public int getDepth() {return depth;}}public TreeNode subtreeWithAllDeepest(TreeNode root) {NodeDepth rootDepth = dfs(root);return rootDepth.getNode();}public NodeDepth dfs(TreeNode node) {if (node == null) {return new NodeDepth(node, 0);}NodeDepth left = dfs(node.left), right = dfs(node.right);TreeNode leftNode = left.getNode(), rightNode = right.getNode();int leftDepth = left.getDepth(), rightDepth = right.getDepth();if (leftDepth == rightDepth) {return new NodeDepth(node, leftDepth + 1);}return leftDepth > rightDepth ? new NodeDepth(leftNode, leftDepth + 1) : new NodeDepth(rightNode, rightDepth + 1);}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。每个结点都被访问一次。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是深度优先搜索的过程中创建实例的空间和递归调用的栈空间,因此空间复杂度是 O ( n ) O(n) O(n)

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

性能测试 —— 性能指标解读与性能分析!

性能测试监控关键指标: 1、系统指标:与⽤户场景与需求直接相关的指标 2、服务器资源指标:硬件服务器的资源使⽤情况的指标 3、JAVA应⽤ : JAVA应⽤程序在运⾏时的各项指标 4、数据库:数据库服务器运⾏时需要监控的指标 5、压测机资源指标:测试机在模拟⽤户负载时的资源使⽤…

VM CentOS7安装ffmpeg

项目中涉及给视频添加水印&#xff0c;使用到了ffmpeg&#xff0c;windows系统可直接使用&#xff0c;Linux需要手动编译完成ffmpeg后才可正常使用。 配置yum源: 备份原repo文件 cd /etc/yum.repos.d/mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.r…

免费图书教材配套资料:Spark大数据技术与应用(第2版)

《Spark大数据技术与应用&#xff08;第2版&#xff09;》课程内容全面介绍了Spark大数据技术的相关知识&#xff0c;内容包含包括Spark概述、Scala基础、Spark编程、Spark编程进阶、Spark SQL结构化数据文件处理、Spark Streaming实时计算框架、Spark GraphX图计算框架、Spark…

推荐一个简单的在线压缩PNG和JPG图片大小的网址

问题描述&#xff1a;推荐一个简单的在线压缩PNG和JPG图片大小的网址 解决&#xff1a; https://www.iloveimg.com/zh-cn/compress-image/compress-png

低代码平台推荐:五大低代码厂商谁的模式更“合适”

随着数字化时代的到来&#xff0c;低代码开发平台作为提高数字生产力的工具正受到越来越多企业的关注&#xff0c;市面上的低代码产品和厂商更是“乱花渐欲迷人眼”。 各家产品不仅功能各有不同&#xff0c;甚至商机都有区别的情况&#xff0c;如何做好产品选型已然成了采购企…

实时截留抖音询价的用户:10个合规方法,让你的业务迅速增长!

先来看实操成果&#xff0c;↑↑需要的同学可看我名字↖↖↖↖↖&#xff0c;或评论888无偿分享 一、引言 随着抖音的普及度越来越高&#xff0c;越来越多的商家开始关注抖音询价用户。这些潜在客户对于企业的发展至关重要&#xff0c;如何实时截留这些用户成为商家关注的重点…

软文推广中如何提炼好产品卖点,媒介盒子分享

内容同质化的时代下&#xff0c;企业应该如何让用户留下印象&#xff0c;并且成功将产品卖出去&#xff0c;核心思维就在于提炼产品卖点&#xff0c;产品卖点是销量提升的关键&#xff0c;相信企业在推广产品时都会有点困惑&#xff0c;感觉自家产品和竞品比起来只是logo、外观…

外设——CAN总线收发器TJA1043

目录 1. 引脚 2. 工作模式 3. 5种模式和7种状态标识的理解和使用 1. 引脚 2. 工作模式 该收发器相较于普通收发器&#xff0c;引脚多了几个&#xff0c;就是功能等多了。TJA1043支持五种操作模式&#xff0c;就是通过控制引脚STB_N和EN来原则。五种模式&#xff1a; 正常模式…

Flink 替换 Logstash 解决日志收集丢失问题

在某客户日志数据迁移到火山引擎使用 ELK 生态的案例中&#xff0c;由于客户反馈之前 Logstash 经常发生数据丢失和收集性能较差的使用痛点&#xff0c;我们尝试使用 Flink 替代了传统的 Logstash 来作为日志数据解析、转换以及写入 ElasticSearch 的组件&#xff0c;得到了该客…

河北专升本(微机原理)

第一章&#xff1a;计算机基础与数制转化 1. 进制运算基础 进位计数制: 按照进位的方法进行计数&#xff0c;称为进位计数制。常见的进位计数制有&#xff1a;二进制、八进制、十进制、十二进制、十六进制等等。 R进制数的特点&#xff1a; 1、具有R个不同的数符。0&#…

Linux使用宝塔面板+Discuz+cpolar内网穿透工具搭建可公网访问论坛

Linux宝塔面板搭建Discuz论坛&#xff0c; 并内网穿透实现公网访问 文章目录 Linux宝塔面板搭建Discuz论坛&#xff0c; 并内网穿透实现公网访问前言1.安装基础环境2.一键部署Discuz3.安装cpolar工具4.配置域名访问Discuz5.固定域名公网地址6.配置Discuz论坛 前言 Crossday Di…

玻色量子“揭秘”之可满足性问题(SAT)与QUBO建模

​ 摘要&#xff1a;布尔可满足性问题&#xff08;Boolean Satisfiability Problem&#xff0c;简称SAT问题&#xff09;是逻辑学和计算机科学中的一个问题&#xff0c;它的目的是确定是否存在一种解释&#xff0c;使给定的布尔公式成立。换句话说&#xff0c;它询问给定布尔公…