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

二叉树的前序遍历

难度:

标签:

题目描述

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

 

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

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

示例 5:

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

 

提示:

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

 

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

代码结果

运行时间: 40 ms, 内存: 14.8 MB


/*
 * 题目思路:
 * 使用 Java Stream 的方式来实现前序遍历。
 * 这种方式主要是将结果流的每一步都显式地分开。
 */
 
import java.util.*;
import java.util.stream.*;
 
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}
 
public class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        if (root == null) return new ArrayList<>();
        return Stream.concat(
            Stream.of(root.val), // 先访问根节点
            Stream.concat(
                preorderTraversal(root.left).stream(), // 再访问左子节点
                preorderTraversal(root.right).stream() // 最后访问右子节点
            )
        ).collect(Collectors.toList());
    }
}

解释

方法:

这个题解使用迭代的方式实现了二叉树的前序遍历。具体思路如下: 1. 如果根节点为空,直接返回空列表 []。 2. 创建一个栈 stack,初始时将根节点压入栈中。 3. 创建一个结果列表 result,用于存储前序遍历的结果。 4. 当栈不为空时,循环执行以下步骤: - 从栈顶弹出一个节点 node。 - 将 node 的值加入结果列表 result。 - 如果 node 的右子节点不为空,将右子节点压入栈中。 - 如果 node 的左子节点不为空,将左子节点压入栈中。 5. 返回结果列表 result,即为二叉树的前序遍历结果。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在迭代方法中优先将右子节点压入栈,而后是左子节点,这样的顺序有什么特别的考虑吗?
在迭代方法中,先将右子节点压入栈然后是左子节点的顺序是为了保证左子节点先被处理。栈是一种后进先出(LIFO)的数据结构,因此最后进栈的元素会最先被访问。在前序遍历中,我们需要按照根-左-右的顺序访问节点。如果我们先将左子节点压入栈,由于栈的这种特性,左子节点会在右子节点之前被弹出并访问,从而满足前序遍历的要求。
🦆
在这个迭代版本的前序遍历中,是否有可能在某些情况下不遵循标准的根-左-右的访问顺序?
在这个迭代版本的前序遍历中,由于左子节点最后被压入栈并因此最先被访问,该实现正确地遵守了标准的根-左-右访问顺序。只要栈的操作顺序保持一致(即总是先压入右子节点,再压入左子节点),就不会出现不遵循标准访问顺序的情况。
🦆
栈结构在这个算法中起到了什么作用,如果改用其他数据结构(如队列),算法会如何变化?
栈结构在这个算法中起到了将访问的节点暂存并控制访问顺序的作用,确保了前序遍历的正确顺序(根-左-右)。如果使用队列代替栈,由于队列是先进先出(FIFO)的数据结构,节点将按照它们被添加到队列的顺序被访问,这将改变节点的访问顺序。具体来说,如果我们仍然按照‘先右后左’的顺序添加子节点到队列,将得到层序遍历的结果,而不是前序遍历。
🦆
题解中提到每个节点最多被访问一次,这种说法是否准确?节点在哪些情况下可能会被访问多次?
在这个迭代前序遍历的实现中,每个节点确实最多只被访问一次,因为每个节点在从栈中弹出时会立即被处理(访问其值并探索其子节点),然后不会再被压回栈中。在一些其他的树遍历算法中,如非递归的中序遍历,节点可能在达到左子树的最底部后再次被访问,以便回溯到其右子树。

相关问题

二叉树的中序遍历

给定一个二叉树的根节点 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]
输出:[1,3,5,6,2,4]

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

 

提示:

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

 

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