145. Binary Tree Postorder Traversal

DFS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
// left -> right -> root

List<Integer> list = new LinkedList<>();
recur(list, root);
return list;
}

private void recur(List<Integer> list, TreeNode node) {
if (node == null) {
return;
}

recur(list, node.left);
recur(list, node.right);
list.add(node.val);
}
}

Iterate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
// left -> right -> root

List<Integer> numList = new ArrayList<>();

Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;
while (!stack.isEmpty() || root != null) {
while (root != null) {
stack.push(root);
root = root.left;
}

// now: root is null
TreeNode node = stack.pop(); // 回溯
// 此时不能添加,因为可能还有 right
if (node.right != null && node.right != pre) {
// 当前节点的右子树不为空,应该先处理右子树,node.right != pre 是为了避免从右子树回到 root 时再次进入右子树
root = node.right; // 进入右子树
stack.push(node); // node 还未收集,所以需要继续入栈
} else {
// 无左子树、右子树,收集该节点值
numList.add(node.val);
pre = node;
}
}

return numList;
}
}

个人认为后序遍历的迭代解法是比较难的。主要有两点需要考虑,一是进入右子树后回退至当前节点的处理逻辑中,要避免重复进入右子树,所以引入了 pre 变量来记录上一个被添加至列表的节点;二是处理右子树之前需要记得把当前节点重新入栈,避免仅处理了右子树导致当前节点未被添加至列表的情况。

References

145. Binary Tree Postorder Traversal