在问 · 算法题解

144. 二叉树的前序遍历

简单二叉树显式栈迭代力扣原题 ↗

题目描述

输入二叉树的根节点 root,按前序遍历的次序返回所有节点值。

前序遍历:先访问当前节点,再前序遍历左子树,最后前序遍历右子树。

空树返回 []。树用层序数组表示,null 代表空位。

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

解释:根 1 没有左孩子,右孩子是 2,3 是 2 的左孩子。

示例 2
输入:root = [1,2,3,4,5,null,8,null,null,6,7,9]
输出:[1,2,4,5,6,7,3,8,9]

解释:先走完左子树 2,4,5,6,7,再走右子树 3,8,9。

示例 3
输入:root = []
输出:[]

解释:空树。

示例 4
输入:root = [1]
输出:[1]

数据范围

  • 节点总数在 [0, 100] 之间。
  • -100 <= Node.val <= 100

进阶:递归写法很直接,能否改用迭代实现?

解题思路:显式栈迭代

用一个显式栈代替递归。弹出栈顶节点就立刻记录它(根先访问),然后先压右孩子、再压左孩子。栈是后进先出的,所以左孩子会先被弹出,整棵左子树处理完后才轮到右孩子。

为什么正确

栈中存的是尚未访问的子树根;栈顶是前序中下一个要访问的节点。

复杂度分析

时间 O(n),空间 O(h)。

易错点

压栈顺序是先右后左,弹出顺序才是先左后右。写反了会得到“根 → 右 → 左”。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        res = []
        stack = [root] if root else []
        while stack:
            node = stack.pop()
            res.append(node.val)
            if node.right:
                stack.append(node.right)
            if node.left:
                stack.append(node.left)
        return res

载入编辑器,自己跑一遍 →

其他解法

递归最简洁,显式栈避免递归深度限制,二者都要 O(h) 到 O(n) 空间;Morris 利用空闲指针把空间降到 O(1)。

解法 2:递归 时间 O(n),空间 O(n)

按照根、左子树、右子树的顺序递归。访问节点时先记录它的值,再依次递归左子树和右子树。

代码最短,直接对应定义。依赖系统调用栈,树退化成链时递归深度为 n。

import sys
from typing import List, Optional

class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        sys.setrecursionlimit(10000)
        res = []

        def dfs(node):
            if not node:
                return
            res.append(node.val)
            dfs(node.left)
            dfs(node.right)

        dfs(root)
        return res

解法 3:Morris 遍历 时间 O(n),空间 O(1)

对当前节点,若无左子树就记录并走向右子树。否则找到左子树中最右边的前驱节点。前驱的 right 为空时,记录当前节点,把前驱指向当前节点后进入左子树。前驱已指向当前节点时,说明左子树已遍历完,恢复指针后走向右子树。

不用栈和递归,额外空间 O(1)。会临时修改树的指针,逻辑较难理解。

from typing import List, Optional

class Solution:
    def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
        res = []
        cur = root
        while cur:
            if not cur.left:
                res.append(cur.val)
                cur = cur.right
                continue
            pre = cur.left
            while pre.right and pre.right is not cur:
                pre = pre.right
            if not pre.right:
                res.append(cur.val)
                pre.right = cur
                cur = cur.left
            else:
                pre.right = None
                cur = cur.right
        return res

二叉树 专题的其他题目

查看 二叉树 全部题目 →