当前位置: 首页 > news >正文

算法leetcode|94. 二叉树的中序遍历(多语言实现)


文章目录

  • 94. 二叉树的中序遍历:
    • 样例 1:
    • 样例 2:
    • 样例 3:
    • 提示:
  • 分析:
  • 题解:
    • rust:
    • go:
    • c++:
    • python:
    • java:


94. 二叉树的中序遍历:

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

样例 1:

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

样例 2:

输入:root = []输出:[]

样例 3:

输入:root = [1]输出:[1]

提示:

  • 树中节点数目在范围 [0, 100]
  • -100 <= Node.val <= 100

分析:

  • 面对这道算法题目,二当家的再次陷入了沉思。
  • 二叉树的中序遍历和前序遍历,后续遍历是二叉树常用的遍历方式。
  • 使用递归方式比循环非递归方式更加简单,直观,易于理解。
  • 通常二叉树的中序遍历一定要使用一个栈结构,因为中序遍历的要求是遍历完左子树才能遍历当前节点,但是遍历到了左子树就无法再回到当前节点了,所以一般都是使用压栈的方式,先将当前节点压栈,遍历完左子树再将当前节点出栈,这样空间复杂度就会是 O(n) (递归也相当于使用了栈结构)。
  • 说起来这不是什么大问题,但是算法就是要想办法优化降低时间和空间的复杂度,于是寄出一种可以将空间复杂度降低为 O(1) 的中序遍历方式,Morris 中序遍历。
  • 事实上Morris 中序遍历不是没有代价的,由于要做额外的节点连接和恢复,相当于用时间换空间。

题解:

rust:

// Definition for a binary tree node.
// #[derive(Debug, PartialEq, Eq)]
// pub struct TreeNode {
//   pub val: i32,
//   pub left: Option<Rc<RefCell<TreeNode>>>,
//   pub right: Option<Rc<RefCell<TreeNode>>>,
// }
//
// impl TreeNode {
//   #[inline]
//   pub fn new(val: i32) -> Self {
//     TreeNode {
//       val,
//       left: None,
//       right: None
//     }
//   }
// }
use std::rc::Rc;
use std::cell::RefCell;
impl Solution {pub fn inorder_traversal(mut root: Option<Rc<RefCell<TreeNode>>>) -> Vec<i32> {let mut ans = Vec::new();while root != None {if root.as_ref().unwrap().borrow().left != None {// 寻找当前 root 节点的前驱节点:前驱 predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止let mut predecessor = root.as_ref().unwrap().borrow().left.clone();while predecessor.as_ref().unwrap().borrow().right != None&& predecessor.as_ref().unwrap().borrow().right != root {predecessor = predecessor.unwrap().borrow().right.clone();}if predecessor.as_ref().unwrap().borrow().right == None {// 让前驱 predecessor 节点的右指针指向当前 root 节点,继续遍历左子树,之后会再次回到当前 root 节点predecessor.unwrap().borrow_mut().right = root.clone();// 遍历左子树root = root.unwrap().borrow().left.clone();continue;} else {// 左子树遍历完毕又回到了当前 root 节点,让前驱 predecessor 节点的右指针与当前 root 节点断开,恢复原样predecessor.unwrap().borrow_mut().right = None;}}// 遍历当前 root 节点ans.push(root.as_ref().unwrap().borrow().val);// 遍历当前 root 节点的右子树root = root.unwrap().borrow().right.clone();}return ans;}
}

go:

/*** Definition for a binary tree node.* type TreeNode struct {*     Val int*     Left *TreeNode*     Right *TreeNode* }*/
func inorderTraversal(root *TreeNode) []int {var ans []intfor root != nil {if root.Left != nil {// 寻找当前 root 节点的前驱节点:前驱 predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止predecessor := root.Leftfor predecessor.Right != nil && predecessor.Right != root {// 有右子树且没有设置过指向 root,则继续向右走predecessor = predecessor.Right}if predecessor.Right == nil {// 让前驱 predecessor 节点的右指针指向当前 root 节点,继续遍历左子树,之后会再次回到当前 root 节点predecessor.Right = root// 遍历左子树root = root.Leftcontinue} else {// 左子树遍历完毕又回到了当前 root 节点,让前驱 predecessor 节点的右指针与当前 root 节点断开,恢复原样predecessor.Right = nil}}// 遍历当前 root 节点ans = append(ans, root.Val)// 遍历当前 root 节点的右子树root = root.Right}return ans
}

c++:

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     TreeNode *left;*     TreeNode *right;*     TreeNode() : val(0), left(nullptr), right(nullptr) {}*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<int> inorderTraversal(TreeNode* root) {vector<int> ans;while (root != nullptr) {if (root->left != nullptr) {// 寻找当前 root 节点的前驱节点:前驱 predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止TreeNode *predecessor = root->left;while (predecessor->right != nullptr && predecessor->right != root) {predecessor = predecessor->right;}if (predecessor->right == nullptr) {// 让前驱 predecessor 节点的右指针指向当前 root 节点,继续遍历左子树,之后会再次回到当前 root 节点predecessor->right = root;// 遍历左子树root = root->left;continue;} else {// 左子树遍历完毕又回到了当前 root 节点,让前驱 predecessor 节点的右指针与当前 root 节点断开,恢复原样predecessor->right = nullptr;}}// 遍历当前 root 节点ans.emplace_back(root->val);// 遍历当前 root 节点的右子树root = root->right;}return ans;}
};

python:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:ans = list()while root is not None:if root.left is not None:# 寻找当前 root 节点的前驱节点:前驱 predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止predecessor = root.leftwhile predecessor.right is not None and predecessor.right != root:# 有右子树且没有设置过指向 root,则继续向右走predecessor = predecessor.rightif predecessor.right is None:# 让前驱 predecessor 节点的右指针指向当前 root 节点,继续遍历左子树,之后会再次回到当前 root 节点predecessor.right = root# 遍历左子树root = root.leftcontinueelse:# 左子树遍历完毕又回到了当前 root 节点,让前驱 predecessor 节点的右指针与当前 root 节点断开,恢复原样predecessor.right = None# 遍历当前 root 节点ans.append(root.val)# 遍历当前 root 节点的右子树root = root.rightreturn ans

java:

/*** Definition for a binary tree node.* public class TreeNode {*     int val;*     TreeNode left;*     TreeNode right;*     TreeNode() {}*     TreeNode(int val) { this.val = val; }*     TreeNode(int val, TreeNode left, TreeNode right) {*         this.val = val;*         this.left = left;*         this.right = right;*     }* }*/
class Solution {public List<Integer> inorderTraversal(TreeNode root) {List<Integer> ans = new ArrayList<Integer>();while (root != null) {if (root.left != null) {// 寻找当前 root 节点的前驱节点:前驱 predecessor 节点就是当前 root 节点向左走一步,然后一直向右走至无法走为止TreeNode predecessor = root.left;while (predecessor.right != null && predecessor.right != root) {predecessor = predecessor.right;}if (predecessor.right == null) {// 让前驱 predecessor 节点的右指针指向当前 root 节点,继续遍历左子树,之后会再次回到当前 root 节点predecessor.right = root;// 遍历左子树root = root.left;continue;} else {// 左子树遍历完毕又回到了当前 root 节点,让前驱 predecessor 节点的右指针与当前 root 节点断开,恢复原样predecessor.right = null;}}// 遍历当前 root 节点ans.add(root.val);// 遍历当前 root 节点的右子树root = root.right;}return ans;}
}

非常感谢你阅读本文~
欢迎【点赞】【收藏】【评论】三连走一波~
放弃不难,但坚持一定很酷~
希望我们大家都能每天进步一点点~
本文由 二当家的白帽子:https://le-yi.blog.csdn.net/ 博客原创~


相关文章:

算法leetcode|94. 二叉树的中序遍历(多语言实现)

文章目录 94. 二叉树的中序遍历&#xff1a;样例 1&#xff1a;样例 2&#xff1a;样例 3&#xff1a;提示&#xff1a; 分析&#xff1a;题解&#xff1a;rust&#xff1a;go&#xff1a;c&#xff1a;python&#xff1a;java&#xff1a; 94. 二叉树的中序遍历&#xff1a; …...

3.[BUUCTF HCTF 2018]WarmUp1

1.看题目提示分析题目内容 盲猜一波~ &#xff1a; 是关于PHP代码审计的 2.打开链接&#xff0c;分析题目 给你提示了我们访问source.php来看一下 大boss出现&#xff0c;开始详细手撕~ 3.手撕PHP代码&#xff08;代码审计&#xff09; 本人是小白&#xff0c;所以第一步&…...

rocky linux9 安装go 即接下去

首先&#xff0c;更新系统的软件包索引以获取最新的软件包信息&#xff1a; sudo dnf update使用以下命令安装 Go 语言&#xff1a; sudo dnf install golang安装完成后&#xff0c;你可以通过以下命令验证 Go 语言是否安装成功&#xff1a; go version4、用相对路径初始化g…...

NLP中的嵌入层

在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;嵌入层&#xff08;Embedding Layer&#xff09;是一个特殊的层&#xff0c;通常用于深度学习模型的第一层&#xff0c;它的作用是将离散的文本数据&#xff08;如单词或短语&#xff09;转换为连续的向量表示。每个单…...

MongoDB文档操作

3.3 文档操作 3.1 文档介绍 文档的数据结构和 JSON 基本一样。 所有存储在集合中的数据都是 BSON 格式。 BSON 是一种类似 JSON 的二进制形式的存储格式&#xff0c;是 Binary JSON 的简称。 文档是一组键值(key-value)对(即 BSON)&#xff0c;一个简单的文档例子如下&…...

解决谷歌浏览器下CSS设置字体小于12px无效办法,关于如何在chrome里实现小于12px的文字。

关于如何在chrome里实现小于12px的文字。 当然文字缩小到12px以下本来就一定程度影响到可用性了&#xff0c;建议无视chrome的这个特性。 谷歌浏览器默认最小字体为12px&#xff0c;小于12px的字体它都以12px显示&#xff0c;有时我们需要字体小点&#xff0c;特别是在制作英文…...

springboot(ssm智慧校园之家长子系统 智慧校园系统Java系统

springboot(ssm0智慧校园之家长子系统 智慧校园系统Java系统 开发语言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#xff08;或8.0&#xff09…...

RM3100 stm32驱动(硬件i2c)

目录 RM3100接线HAL库I2C函数HAL_I2C_Mem_ReadHAL_I2C_Mem_WriteHAL_I2C_Master_Transmit / HAL_I2C_Master_Receive例子 HSHAKE寄存器 cubemx配置RM3100寄存器驱动最终效果 RM3100接线 原理图 SA0 SA1接地&#xff0c;此时i2c设备地址为0100000&#xff0c;即0x20 如果SA0接…...

视觉学习(7) —— 接收数据和发送数据以及全局变量和浮点数

1、前提 创建一个四个字节的地址 2、发送数据 &#xff08;1&#xff09;直接发送数据 再观察地址里的值 与我们想要值不一样 输入0&#xff0c;而实际值则为 结论&#xff1a;直接输入值到地址&#xff0c;值会发生变化 &#xff08;2&#xff09;走全局变量发送数据 添加全…...

leetcode 1576. 替换所有的问号(easy)(优质解法)

链接&#xff1a;1576. 替换所有的问号 代码&#xff1a; class Solution {public String modifyString(String s) {char[] charSs.toCharArray();int lengthcharS.length;//遍历找到 &#xff1f;for(int i0;i<length;i){if(charS[i]?){//遍历 a ~ z 选择一个合适的字符来…...

Advanced IP Scanner - 网络扫描器

Advanced IP Scanner - 网络扫描器 1. Advanced IP ScannerReferences https://www.advanced-ip-scanner.com/cn/ ​ 可靠且免费的网络扫描器可以分析 LAN。该程序可扫描所有网络设备&#xff0c;使您能够访问共享文件夹和 FTP 服务器&#xff0c;(通过 RDP 和 Radmin) 远程控制…...

搜索百度百科官方创建入口,怎么创建更新公司的百度百科词条呢?

在百度搜索百度百科找到百度百科官方创建入口&#xff0c;可以上传并创建公司类的百度百科词条&#xff0c;创建词条后还可以再修改更新百科词条&#xff0c;最终完善好的百度百科词条将会在百度上获得大量曝光。那么百度百科可以怎么创建&#xff0c;下面洛希爱做百科网把十多…...

大数据与人工智能|全面数字化战略与企业数字化转型(第1节 )

要点一&#xff1a;培养跨学科思维 在分析时&#xff0c;需要采用多学科的思维方式 结果不重要&#xff0c;重要的是如何提炼现象、分析问题和得出结论的过程。 1. 介绍了锤子精神和多学科思维方式的重要性。指出了只从自身学科出发解决问题的局限性。 2. 提倡跨学科思维方式&a…...

【四】【C语言\动态规划】地下城游戏、按摩师、打家劫舍 II,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略&#xff0c;它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题&#xff0c;并将每个小问题的解保存起来。这样&#xff0c;当我们需要解决原始问题的时候&#xff0c;我们就可以直接利…...

【大数据存储与处理】开卷考试总复习笔记

文章目录 实验部分一、 HBase 的基本操作1. HBase Shell入门2. HBase创建数据库表3. HBase数据操作4. HBase删除数据库表5. HBase Python基本编程 before二、 HBase 过滤器操作1.创建表和插入数据2.行键过滤器3.列族与列过滤器4.值过滤器5.其他过滤器6.python hbase 过滤器编程…...

HTML 实操试题(一)

创建一个包含标题、段落和链接的基本HTML文档&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><ti…...

创龙瑞芯微RK3568设备树1(修改设备树GPIO和串口)

前言 最近一直在搞3568的东西&#xff0c;涉及到底层的设备树修改&#xff0c;驱动编写等等&#xff0c;忙的焦头烂额的&#xff0c;也没时间往下面写东西了。今天差不多底层的东西快弄完了&#xff0c;把最近的感悟给大家分享下&#xff0c;并且加入点设备树的基础知识。给刚刚…...

R语言【dplyr】——filter保留符合筛选条件的行,以数据的行为单位,创建子集

Package dplyr version 1.1.4 Parameters filter(.data, ..., .by NULL, .preverse FALSE) 参数【.data】&#xff1a;一个数据集&#xff08;data frame&#xff09;&#xff0c;数据集扩展&#xff08;比如&#xff1a;tibble&#xff09;&#xff0c;或者 lazy data fra…...

几种串口扩展电路

一、IIC串口扩展电路 LCT200 是一款可以通过 I2C 接口通讯&#xff0c;拓展 2 路独立串口的通讯芯片&#xff0c;同时也支持通过 2 路串口读写 I2C 接口的数据。LCT200 的封装为 TSSOP-20。 主要功能&#xff1a;⚫ 通过对 I2C 接口读写实现拓展 2 路独立串口功能 ⚫ 通过读写…...

实战10 角色管理

目录 1、角色后端接口 2、角色列表查询 2.1 效果图 2.2页面原型代码 2.3 角色api代码 role.js 2.4 查询角色列表代码 4、 新增和编辑角色 5、删除角色 6、分配权限 6.1 分配权限思路 6.2 分配权限回显接口 6.3 分配权限回显前端实现 6.4分配权限后端接口 6.4.1 R…...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

golang循环变量捕获问题​​

在 Go 语言中&#xff0c;当在循环中启动协程&#xff08;goroutine&#xff09;时&#xff0c;如果在协程闭包中直接引用循环变量&#xff0c;可能会遇到一个常见的陷阱 - ​​循环变量捕获问题​​。让我详细解释一下&#xff1a; 问题背景 看这个代码片段&#xff1a; fo…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

QT: `long long` 类型转换为 `QString` 2025.6.5

在 Qt 中&#xff0c;将 long long 类型转换为 QString 可以通过以下两种常用方法实现&#xff1a; 方法 1&#xff1a;使用 QString::number() 直接调用 QString 的静态方法 number()&#xff0c;将数值转换为字符串&#xff1a; long long value 1234567890123456789LL; …...

【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)

1.获取 authorizationCode&#xff1a; 2.利用 authorizationCode 获取 accessToken&#xff1a;文档中心 3.获取手机&#xff1a;文档中心 4.获取昵称头像&#xff1a;文档中心 首先创建 request 若要获取手机号&#xff0c;scope必填 phone&#xff0c;permissions 必填 …...