二叉树题目:二叉树的中序遍历

news2024/11/23 22:47:01

文章目录

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

题目

标题和出处

标题:二叉树的中序遍历

出处:94. 二叉树的中序遍历

难度

3 级

题目描述

要求

给你二叉树的根结点 root \texttt{root} root,返回其结点值的中序遍历。

示例

示例 1:

示例 1

输入: root   =   [1,null,2,3] \texttt{root = [1,null,2,3]} root = [1,null,2,3]
输出: [1,3,2] \texttt{[1,3,2]} [1,3,2]

示例 2:

输入: root   =   [] \texttt{root = []} root = []
输出: [] \texttt{[]} []

示例 3:

输入: root   =   [1] \texttt{root = [1]} root = [1]
输出: [1] \texttt{[1]} [1]

数据范围

  • 树中结点数目在范围 [0,   100] \texttt{[0, 100]} [0, 100]
  • -100 ≤ Node.val ≤ 100 \texttt{-100} \le \texttt{Node.val} \le \texttt{100} -100Node.val100

进阶

递归解法很简单,你可以使用迭代解法完成吗?

解法一

思路和算法

二叉树的中序遍历的方法为:依次遍历左子树、根结点和右子树,对于左子树和右子树使用同样的方法遍历。由于遍历过程具有递归的性质,因此可以使用递归的方法实现二叉树的中序遍历。

递归的终止条件是当前结点为空。对于非终止条件,递归的做法如下。

  1. 对当前结点的左子树调用递归。

  2. 将当前结点的结点值加入中序遍历序列。

  3. 对当前结点的右子树调用递归。

遍历结束之后即可得到中序遍历序列。

代码

class Solution {
    List<Integer> traversal = new ArrayList<Integer>();

    public List<Integer> inorderTraversal(TreeNode root) {
        inorder(root);
        return traversal;
    }

    public void inorder(TreeNode node) {
        if (node == null) {
            return;
        }
        inorder(node.left);
        traversal.add(node.val);
        inorder(node.right);
    }
}

复杂度分析

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

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是递归调用的栈空间,取决于二叉树的高度,最坏情况下二叉树的高度是 O ( n ) O(n) O(n)

解法二

思路和算法

使用迭代的方法实现二叉树的中序遍历,则需要使用栈存储结点。

从根结点开始遍历,遍历的终止条件是栈为空且当前结点为空。遍历的做法如下。

  1. 如果当前结点不为空,则将当前结点入栈,然后将当前结点移动到其左子结点,重复该操作直到当前结点为空。

  2. 将一个结点出栈,将当前结点设为出栈结点,将当前结点的结点值加入中序遍历序列。

  3. 将当前结点移动到其右子结点。

  4. 重复上述操作,直到达到遍历的终止条件。

代码

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> traversal = new ArrayList<Integer>();
        Deque<TreeNode> stack = new ArrayDeque<TreeNode>();
        TreeNode node = root;
        while (!stack.isEmpty() || node != null) {
            while (node != null) {
                stack.push(node);
                node = node.left;
            }
            node = stack.pop();
            traversal.add(node.val);
            node = node.right;
        }
        return traversal;
    }
}

复杂度分析

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

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。空间复杂度主要是栈空间,取决于二叉树的高度,最坏情况下二叉树的高度是 O ( n ) O(n) O(n)

解法三

思路和算法

莫里斯遍历是使用常数空间遍历二叉树的方法,由 J. H. Morris 提出。莫里斯遍历的核心思想是利用二叉树的空闲指针维护遍历顺序,达到省略栈空间的目的。

从根结点开始遍历,遍历的终止条件是当前结点为空。

对于每个结点,判断当前结点的左子树是否为空,执行相应的操作。

  • 如果当前结点的左子树为空,则将当前结点的结点值加入中序遍历序列,将当前结点移动到其右子结点。

  • 如果当前结点的左子树不为空,则找到当前结点的前驱结点,前驱结点为当前结点的左子树中的最右边的结点,判断前驱结点的右子结点是否为空。

    • 如果前驱结点的右子结点为空,则将前驱结点的右子结点设为当前结点,将当前结点移动到其左子结点。

    • 如果前驱结点的右子结点不为空,则将前驱结点的右子结点设为空,将当前结点的结点值加入中序遍历序列,将当前结点移动到其右子结点。

重复上述操作,直到达到遍历的终止条件。

代码

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> traversal = new ArrayList<Integer>();
        TreeNode node = root;
        while (node != null) {
            if (node.left == null) {
                traversal.add(node.val);
                node = node.right;
            } else {
                TreeNode predecessor = node.left;
                while (predecessor.right != null && predecessor.right != node) {
                    predecessor = predecessor.right;
                }
                if (predecessor.right == null) {
                    predecessor.right = node;
                    node = node.left;
                } else {
                    predecessor.right = null;
                    traversal.add(node.val);
                    node = node.right;
                }
            }
        }
        return traversal;
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是二叉树的结点数。使用莫里斯遍历,每个结点最多被访问两次。

  • 空间复杂度: O ( 1 ) O(1) O(1)。注意返回值不计入空间复杂度。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows Terminal添加至鼠标右键

Windows Terminal添加至鼠标右键 安装 在Microsoft Store中即可下载。 配置 在鼠标右键打开 下载Terminal图标 图标地址:https://raw.githubusercontent.com/microsoft/terminal/master/res/terminal.ico 下载后保存在某个文件夹path 添加到鼠标右键 批处理修改注册表 …

Linux常见指令(超详解哦)

Linux常见指令 引言Linux常见指令查指令——man文件管理相关指令lspwdcdtouchmkdirrmdir与rmrmdirrm cpmvfind 文件查看类catmorelesshead 与 tailheadtail使用管道显示某段内容 grep 打包压缩相关指令zip/unziptar 总结 引言 Linux与我们熟悉的Window都是操作系统&#xff0c…

spring-aop入门

spring-aop入门 什么是AOP OOP(Object-Oriented Programming)面向对象编程&#xff0c;允许开发者定义纵向的关系&#xff0c;但并适用于定义横向的关系&#xff0c;导致了大量代码的重复&#xff0c;而不利于各个模块的重用。 AOP(Aspect-Oriented Programming)&#xff0c;…

优思学院|质量管理六大思维陷阱【五】:有了控制图就能改进质量?

1. 引言 在工厂的生产过程中&#xff0c;质量控制是至关重要的。控制图是一种常见的质量管理工具&#xff0c;它可以帮助工厂监测过程的稳定性和质量表现&#xff0c;同时它也是六西格玛最重要的工具之一。然而&#xff0c;人们对于控制图的理解并不总是正确&#xff0c;有时被…

【中危】Kubernetes secrets-store-csi-driver 信息泄露漏洞

漏洞描述&#xff1a; Kubernetes secrets-store-csi-driver 是一个用于 Kubernetes 的 CSI 驱动程序&#xff0c;它提供了一种将外部密钥存储系统中的凭据注入到 Kubernetes Pod 的机制。 在 secrets-store-csi-driver 受影响版本中&#xff0c;当在 CSIDriver 对象中配置了…

操作系统期末复习简记(更新中~)

文件 定义&#xff1a;文件是以计算机硬盘为载体的存储在计算机上的信息集合&#xff08;宽泛的&#xff09; 属性&#xff1a;描述文件状态的信息&#xff0c;eg.名称&#xff0c;修改时间等等 基本操作&#xff1a;创建、打开、修改文件 文件的逻辑结构 1、无结构文件&#x…

【SpringMVC】统一异常处理 前后台协议联调 拦截器(文末赠书)

1&#xff0c;统一异常处理 1. 问题描述 在讲解这一部分知识点之前&#xff0c;我们先来演示个效果&#xff0c;修改BookController类的getById方法 GetMapping("/{id}") public Result getById(PathVariable Integer id) {//手动添加一个错误信息if(id1){int i …

JS BOM和DOM对象的尺寸

A scroll…..系列 scrollHeight: 获取对象的滚动高度。 scrollWidth:获取对象的滚动宽度 scrollLeft:设置或获取位于对象左边界和窗口中目前可见内容的最左端之间的距离 内容距左边框的距离(不算padding与border) scrollTop:设置或获取位于对象最顶端和窗口中可见内容的最…

智慧景区预约系统开发 实现游客自助游玩

旅游是我们休闲娱乐的重要手段之一&#xff0c;尤其是疫情放开以来&#xff0c;旅游成为很多人节假日的首选。绝大多数的旅游景区都是需要购票参观的&#xff0c;对于景区来说也是卖出的票越多&#xff0c;盈利越多。所以各大景区也一直都在拓展新的售票渠道来提升旅客数量。通…

JavaScript基础笔记

JavaScript 介绍 JavaScript 是什么 1JavaScript 书写位置 JavaScript 注释 JavaScript 结束符 JavaScript 输入输出语法 变量 变量是什么&#xff1f; 变量的基本使用 变量的本质 变量命名规则与规范 数组的基本使用 常量 数据类型 数据类型 – 数字类型&#xff08;Number&…

基于ICA算法的图像融合matlab完整程序分享

用特定的算法将两幅或多幅图像综合成一幅新的图像。融合结果由于能利用两幅(或多幅) 图像在时空上的相关性及信息上的互补性,并使得融合后得到的图像对场景有更全面、清晰的描述,从而更有利于人眼的识别和机器的自动探测。 确保待融合图像已配准好且像素位宽一致,且融…

《向量数据库》——Milvus v1.0 已发布

Milvus v1.0 已发布 今天,我们很高兴地宣布 Milvus v1.0 版本的发布。通过数百名 Milvus 社区用户在八个月内不断的测试和试验, Milvus v0.10.x 现在已足够稳定,是时候该发布基于 Milvus v0.10.6 的 Milvus v1.0 了。 Milvus v1.0 具有以下功能: 支持主流的相似度计算方式…

软件测试CMA认证和CNAS认可分别有什么作用?

随着信息化时代的飞速发展&#xff0c;软件已经成为各行各业必不可少的工具。但是&#xff0c;随之而来的问题就是软件的质量问题&#xff0c;尤其是安全问题。这就需要软件测试行业的发展。而软件测试CMA认证和CNAS认可对于软件测试企业来说&#xff0c;是非常重要的两个证书。…

Android classLoader 双亲委托 反射 类加载

双亲委托 双亲委托机制&#xff0c;就是导入类的时候判断parent是否已经导入过该类。 作用 1、避免重复加载&#xff0c;当父加载器已经加载了该类的时候&#xff0c;没有必要子ClassLoader再加载一次。 2、安全性考虑&#xff0c;防止核心API库被随意篡改。 核心代码 pri…

java【String类的常用方法】

String类 String类的常用方法1 字符串的构造方法2 String对象的比较3 字符串查找4 字符串与其他类型的转换4.1 字符串和数值互相转换4.2 大小写转换4.3 字符串转数组4.4 字符串格式化 5 字符串的替换6 字符串的截取操作7 字符串的拆分8 字符串去除空格trim()方法 String类的常用…

费报只是小 case!电子影像系统,工作效率up无限

在日常工作中,我发现许多朋友对电子影像系统存有一个错误认知,“电子影像系统,我了解,就是用来做费用报销的吧”。 但事实上,电子影像系统的实用价值远非这样,它可以解决企业许多业务场景中的难点。今天,让我们一起来探讨电子影像系统,希望能对大家在企业数字化改革中带来更多帮…

spring security oauth2学习 -- 快速入门

1.Oauth2认证协议 简单理解&#xff1a; OAuth2是目前最流行的授权协议&#xff0c;用来授权第三方应用&#xff0c;获取用户数据。 1.1 流程 客户端通过认证和授权&#xff0c;向资源服务器去访问资源。 其中&#xff0c;授权和认证都需要在授权服务器&#xff0c;由资源拥…

【Java】parallelStream().forEach() 的踩坑日记

文章目录 前言踩坑日记刨根问底解决方案小结 前言 最近一直在开发项目中的新需求&#xff0c;其中有一个需求是“解析文件&#xff08;.txt文件&#xff0c;一行就是一条数据&#xff09;中的数据并进行入库操作”。其实这个需求也很简单&#xff0c;无非就是将文件中每一行数…

架构师必须掌握的架构设计原则

如果一个架构或设计原则已经存在 15 年&#xff0c;例如单一职责和依赖倒置原则&#xff0c;我可以预期它还有 15 年甚至更久的生命期。原则是比具体技术更抽象&#xff0c;更接近事物本质&#xff0c;也更经得起时间考验的东西。这些原则沉淀在架构师的脑海中&#xff0c;最终…

彻底理解 linux 的内存回收

本文试图用最浅显的语言说明以下问题&#xff1a; 1、free 命令中的buffer/cache 是什么意思&#xff1f; 2、内存回收的机制是什么&#xff1f; 3、内存回收的门限是什么&#xff1f;也就是什么时候进行回收&#xff1f; 4、如何手动清除cache&#xff1f; 1、free 命令中的bu…