leetcode
leetcode 101 ~ 150
二叉树的后序遍历

二叉树的后序遍历

难度:

标签:

题目描述

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

 

示例 1:

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

示例 2:

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

示例 3:

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

 

提示:

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

 

进阶:递归算法很简单,你可以通过迭代算法完成吗?

代码结果

运行时间: 44 ms, 内存: 14.9 MB


/*
 * 题目思路:
 * 1. 使用Java Stream API来实现后序遍历。
 * 2. 将树节点转化为流,然后进行操作。
 */
 
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int val) { this.val = val; }
}
 
public class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        // 如果根节点为空,则返回空列表
        if (root == null) return new ArrayList<>();
        return Stream.concat(
                postorderTraversal(root.left).stream(), // 左子树
                postorderTraversal(root.right).stream() // 右子树
        ).collect(Collectors.toList());
    }
}

解释

方法:

这个题解使用了迭代的方式实现二叉树的后序遍历。具体思路如下: 1. 如果根节点为空,直接返回空列表。 2. 初始化一个栈,并将根节点压入栈中。 3. 初始化一个结果列表 `result`,用于存储后序遍历的节点值。 4. 当栈不为空时,循环执行以下操作: - 弹出栈顶节点,并将其值追加到结果列表 `result` 的尾部。 - 如果该节点有左子节点,将左子节点压入栈中。 - 如果该节点有右子节点,将右子节点压入栈中。 5. 由于后序遍历的顺序是左-右-根,而我们在将节点值追加到结果列表时,顺序是根-右-左,因此需要将结果列表反转后返回。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在迭代过程中,为什么首先将根节点值加入结果列表,而不是直接遵循后序遍历的左-右-根顺序?
在迭代方法中,直接遵循后序遍历的左-右-根顺序较为复杂,因为需要在遍历过程中不断地检查节点是否已经被访问过。通过先将根节点值加入结果列表,再按根-右-左的顺序处理子节点,我们可以利用栈的后进先出特性来简化这一过程。这种处理方式允许我们不用标记节点的访问状态,从而简化代码。最后通过反转列表,使得结果符合后序遍历的左-右-根顺序。
🦆
在迭代实现中,左子节点和右子节点被添加到栈中的顺序为何如此重要,尤其是对于最终结果的影响?
在迭代实现中,顺序非常关键,因为我们最终需要的输出顺序是左-右-根。首先处理根节点,然后将右子节点压入栈,接着压入左子节点。这样做是为了确保左子节点在栈中位于右子节点之上,以便它能在右子节点之前被处理和弹出。这个顺序是反向处理的,因为栈是一种后进先出的数据结构。
🦆
结果列表需要在最后被反转。这种方法相比于直接按后序遍历顺序添加结果的优势在哪里?
使用迭代方法并在最后反转结果列表的主要优势是简化了操作逻辑和实现复杂度。如果尝试直接在迭代过程中按照后序遍历的顺序添加结果,我们需要频繁地检查每个节点是否已经处理过其子节点,这通常需要额外的数据结构如哈希表来记录这些信息。通过先根-右-左的顺序添加,然后简单地反转列表,我们避免了这种复杂性,并利用了栈这一数据结构的天然属性。
🦆
迭代方法通常比递归方法有什么优势和劣势,特别是在处理树的遍历时?
迭代方法的优势在于它通常使用显式的栈来控制调用过程,这可以避免递归带来的栈溢出的风险,尤其是在处理深度很大的树时。此外,迭代方法的空间复杂度更易于控制。然而,迭代的劣势在于实现上通常比递归复杂,可读性和维护性可能较差。递归方法的代码更加直观和简洁,特别是对于树这种天然具有递归结构的数据结构。

相关问题

二叉树的中序遍历

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

 

示例 1:

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

示例 2:

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

示例 3:

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

 

提示:

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

 

进阶: 递归算法很简单,你可以通过迭代算法完成吗?

N 叉树的后序遍历

给定一个 n 叉树的根节点 root ,返回 其节点值的 后序遍历

n 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔(请参见示例)。

 

示例 1:

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

示例 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]
输出:[2,6,14,11,7,3,12,8,4,13,9,10,5,1]

 

提示:

  • 节点总数在范围 [0, 104]
  • 0 <= Node.val <= 104
  • n 叉树的高度小于或等于 1000

 

进阶:递归法很简单,你可以使用迭代法完成此题吗?