LeetCode 590简单树 · BST
N 叉树的后序遍历 图解题解
这道题到底在问什么
给定 N 叉树根节点 root,返回它所有节点值的后序遍历序列。N 叉树里一个节点可以有任意多个孩子,孩子按从左到右的顺序排列。后序 = 先递归走完每个孩子,再把当前节点收进结果。
- 输入
- root = [1,null,3,2,4,null,5,6]
- 输出
- [5,6,3,2,4,1]
最优解:一步一步想明白
- 3记住「先遍历孩子列表、最后收根」这一条,下面每一帧都在套它。
- 4后序序列还是空的开局后序序列为空。DFS 从根节点 50 出发,口诀是先把孩子走完再收自己,我们一路往下探。
- 5先处理 50 的孩子走到节点 50(紫色)。它的孩子列表是 30、80,按后序规矩,要先把这些孩子从左到右一个个递归走完,50 自己留到最后再收。
- 6先处理 30 的孩子走到节点 30(紫色)。它的孩子列表是 10、20,按后序规矩,要先把这些孩子从左到右一个个递归走完,30 自己留到最后再收。
- 7先处理 10 的孩子走到节点 10(紫色)。它的孩子列表是 15、25,按后序规矩,要先把这些孩子从左到右一个个递归走完,10 自己留到最后再收。
- 815 没有孩子走到节点 15(紫色)。它的孩子列表是空的,是个叶子,没有可往下走的孩子,马上就能收它。
- 915 入列,后序 +1叶子 15 没有孩子要等,直接把它追加进后序序列(变绿),目前序列是 15。
- 1025 没有孩子走到节点 25(紫色)。它的孩子列表是空的,是个叶子,没有可往下走的孩子,马上就能收它。
- 1125 入列,后序 +1叶子 25 没有孩子要等,直接把它追加进后序序列(变绿),目前序列是 15 25。
- 1210 入列,后序 +110 的孩子 15、25 都已经收完了,现在轮到 10 自己。把 10 追加进后序序列(变绿),目前序列是 15 25 10。
- 1320 没有孩子走到节点 20(紫色)。它的孩子列表是空的,是个叶子,没有可往下走的孩子,马上就能收它。
- 1420 入列,后序 +1叶子 20 没有孩子要等,直接把它追加进后序序列(变绿),目前序列是 15 25 10 20。
- 1530 入列,后序 +130 的孩子 10、20 都已经收完了,现在轮到 30 自己。把 30 追加进后序序列(变绿),目前序列是 15 25 10 20 30。
- 16先处理 80 的孩子走到节点 80(紫色)。它的孩子列表是 70、90,按后序规矩,要先把这些孩子从左到右一个个递归走完,80 自己留到最后再收。
- 17先处理 70 的孩子走到节点 70(紫色)。它的孩子列表是 75、78,按后序规矩,要先把这些孩子从左到右一个个递归走完,70 自己留到最后再收。
- 1875 没有孩子走到节点 75(紫色)。它的孩子列表是空的,是个叶子,没有可往下走的孩子,马上就能收它。
- 1975 入列,后序 +1叶子 75 没有孩子要等,直接把它追加进后序序列(变绿),目前序列是 15 25 10 20 30 75。
- 2078 没有孩子走到节点 78(紫色)。它的孩子列表是空的,是个叶子,没有可往下走的孩子,马上就能收它。
- 2178 入列,后序 +1叶子 78 没有孩子要等,直接把它追加进后序序列(变绿),目前序列是 15 25 10 20 30 75 78。
- 2270 入列,后序 +170 的孩子 75、78 都已经收完了,现在轮到 70 自己。把 70 追加进后序序列(变绿),目前序列是 15 25 10 20 30 75 78 70。
- 2390 没有孩子走到节点 90(紫色)。它的孩子列表是空的,是个叶子,没有可往下走的孩子,马上就能收它。
- 2490 入列,后序 +1叶子 90 没有孩子要等,直接把它追加进后序序列(变绿),目前序列是 15 25 10 20 30 75 78 70 90。
- 2580 入列,后序 +180 的孩子 70、90 都已经收完了,现在轮到 80 自己。把 80 追加进后序序列(变绿),目前序列是 15 25 10 20 30 75 78 70 90 80。
- 2650 入列,后序 +150 的孩子 30、80 都已经收完了,现在轮到 50 自己。把 50 追加进后序序列(变绿),目前序列是 15 25 10 20 30 75 78 70 90 80 50。
- 27答案 = [15, 25, 10, 20, 30, 75, 78, 70, 90, 80, 50]整棵树走完,所有节点都收进了后序序列:15 25 10 20 30 75 78 70 90 80 50。可以看到每个节点都在自己的孩子全部收完之后才入列,根 50 排在最后,这就是后序的特征。
⚠️ 容易写错的地方
✗ 错:把当前节点先收了再走孩子
✓ 对:后序必须孩子全收完才收自己
先收自己就变成了前序,顺序整个错
✗ 错:孩子顺序写反(从右到左)
✓ 对:按列表从左到右递归
后序里同层孩子的相对顺序由从左到右决定
✗ 错:忘了判空 / 空树没处理
✓ 对:node 为空直接返回
空树应返回空列表,不判空会越界或报错
完整代码(Python / C++ / Java)
Python
from typing import List
class Node:
def __init__(self, val=None, children=None):
self.val = val
self.children = children if children is not None else []
class Solution:
def postorder(self, root: 'Node') -> List[int]:
ans = []
def dfs(node):
if not node:
return
for child in node.children:
dfs(child)
ans.append(node.val)
dfs(root)
return ansC++
#include <algorithm>
#include <functional>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
class Node {
public:
int val;
vector<Node*> children;
Node() {}
Node(int _val) { val = _val; }
Node(int _val, vector<Node*> _children) { val = _val; children = _children; }
};
class Solution {
public:
vector<int> postorder(Node* root) {
vector<int> ans;
function<void(Node*)> dfs = [&](Node* node) {
if (!node) return;
for (Node* child : node->children) dfs(child);
ans.push_back(node->val);
};
dfs(root);
return ans;
}
};Java
import java.util.*;
class Node {
public int val;
public List<Node> children;
public Node() { children = new ArrayList<>(); }
public Node(int _val) { val = _val; children = new ArrayList<>(); }
public Node(int _val, List<Node> _children) { val = _val; children = _children; }
}
class Solution {
public List<Integer> postorder(Node root) {
ArrayList<Integer> ans = new ArrayList<>();
dfs(root, ans);
return ans;
}
private void dfs(Node node, List<Integer> ans) {
if (node == null) return;
for (Node child : node.children) dfs(child, ans);
ans.add(node.val);
}
}复杂度
时间
O(n)
每个节点恰好被访问一次:进入一次、收一次,n 个节点就是 O(n)
空间
O(h)
递归栈深度等于树高 h;最坏退化成一条链时 h = n,即 O(n)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 N 叉树的后序遍历 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
进阶要求用迭代法,怎么做?+
一个常用技巧是「改良前序再反转」:用一个栈,每次弹出节点就把它的值记进结果,并把它的孩子按从左到右的顺序压栈(这样栈顶先出的是最右孩子)。这样得到的序列是「根在前」的逆后序,最后把整个结果数组反转一次,就是正确的后序。另一种是显式用栈模拟递归、记录每个节点孩子处理到第几个。
为什么递归空间是 O(h) 而不是 O(n)?+
递归栈在任意时刻只保存「从根到当前节点」这一条路径上的调用帧,深度等于当前节点的层数,最多就是树高 h。只有当树退化成一条链时 h 才等于 n,所以一般记 O(h),最坏 O(n)。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 N 叉树的后序遍历 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。