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

LeetCode - 145. 二叉树的后序遍历

目录

题目

什么是后序遍历

递归写法

非递归写法

思路

过程

正确写法


题目

145. 二叉树的后序遍历 - 力扣(LeetCode)

什么是后序遍历

后序遍历(Post-order Traversal)是二叉树的三种主要遍历方式之一,遵循"左-右-根"的访问顺序:

  • 首先遍历左子树(递归)
  • 然后遍历右子树(递归)
  • 最后访问根节点

简单来说,在后序遍历中,一个节点只有在其左右子树都被访问完后才会被访问。

    1/ \2   3/ \   \
4   5   6

后序遍历的结果是:[4, 5, 2, 6, 3, 1]

遍历过程:

  • 访问左子树:先访问4,然后是5,最后是2
  • 访问右子树:先访问6,然后是3
  • 最后访问根节点1

递归写法

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {vector<int> result;dfs(root,result);return result;}void dfs(TreeNode* root, vector<int>& result){if(!root){return;}dfs(root->left,result);dfs(root->right,result);result.push_back(root->val);}};

非递归写法

采用两个栈来模拟实现左-右-根

思路

反序构建:

  • 使用第一个栈(s1)进行类似前序遍历的操作,但是入栈顺序改为"先左后右"
  • 这样从s1出栈的顺序就变成了"根-右-左"
  • 将从s1出栈的元素依次压入第二个栈(s2)
  • s2出栈时的顺序就是"左-右-根",正好是后序遍历的顺序

操作步骤:

  • 将根节点压入s1
  • 当s1不为空时:
  • 弹出s1栈顶节点并压入s2
  • 将该节点的左子节点压入s1(如果存在)
  • 将该节点的右子节点压入s1(如果存在)
  • 当s1为空时,依次从s2弹出元素,这就是后序遍历的结果

原理解释:

  • 第一个栈(s1)用于遍历树并产生"根-右-左"的顺序
  • 第二个栈(s2)用于反转这个顺序,变成"左-右-根"
  • 本质上是利用栈的后进先出特性,将一种顺序转换为它的反序

过程

步骤1:将根节点1压入s1

s1: [1]
s2: []

步骤2:弹出s1栈顶元素1,压入s2,然后将1的子节点压入s1(先左后右)

s1: [2, 3]  // 先左后右
s2: [1]

步骤3:弹出s1栈顶元素3,压入s2,然后将3的子节点压入s1

s1: [2, 6]  // 3只有右子节点
s2: [1, 3]

步骤4:弹出s1栈顶元素6,压入s2(6没有子节点)

s1: [2]
s2: [1, 3, 6]

步骤5:弹出s1栈顶元素2,压入s2,然后将2的子节点压入s1

s1: [4, 5]  // 2的左右子节点
s2: [1, 3, 6, 2]

步骤6-7:处理4和5(它们没有子节点)

s1: []
s2: [1, 3, 6, 2, 5, 4]

步骤8:从s2中依次弹出元素得到结果

result = [4, 5, 2, 6, 3, 1]

正确写法

class Solution {
public:vector<int> postorderTraversal(TreeNode* root) {//根在右,子在左vector<int> result;if(!root){return result;}stack<TreeNode*> st1;stack<TreeNode*> st2; st1.push(root);while(!st1.empty()){TreeNode* node = st1.top();st1.pop();st2.push(node);if(node->left){st1.push(node->left);}if(node->right){st1.push(node->right);}}while(!st2.empty()){TreeNode* cur = st2.top();result.push_back(cur->val);st2.pop();}return result;}
};
http://www.xdnf.cn/news/12846.html

相关文章:

  • JavaScript 内置对象全解析
  • QRadioButton(续)+ CheckBox + QLabel(2)
  • 【Go语言基础【20】】Go的包与工程
  • c#,Powershell,mmsys.cpl,使用Win32 API展示音频设备属性对话框
  • JavaWeb预习(jdbc)
  • 拼多多官方内部版 7.58.0 | 极限精简,只有2.5M
  • 【笔记】Poetry虚拟环境创建示例
  • Prompt Tuning(提示调优)到底训练优化的什么部位
  • DiscuzX3.5发帖json api
  • maven 1.0.0idea的使用说明
  • Vue3学习(watchEffect,标签的ref属性,计数器,defineExpose)
  • SpringCloud学习笔记-4
  • 实验二:数码管动态显示实验
  • 建造者模式深度解析与实战应用
  • WEB3技术重要吗,还是可有可无?
  • STM32入门学习之系统时钟配置
  • K8S认证|CKS题库+答案| 7. Dockerfile 检测
  • 五、jmeter脚本参数化
  • PHP中如何定义常量以及常量和变量的主要区别
  • Spark流水线+Gravitino+Marquez数据血缘采集
  • java综合项目开发一课一得
  • 使用 Melos 高效管理 Flutter/Dart Monorepo 项目
  • 用 Melos 解决 Flutter Monorepo 的依赖冲突:一个真实案例
  • Python 包管理器 uv 介绍
  • 基于PostGIS的各地级市路网长度统计及Echarts图表可视化实践-以湖南省为例
  • 支持selenium的chrome driver更新到137.0.7151.68
  • 时序数据库IoTDB结合SeaTunnel实现高效数据同步
  • 七、Sqoop Job:简化与自动化数据迁移任务及免密执行
  • Ubuntu20.04中 Redis 的安装和配置
  • 通过Cline使用智能体