590. N-ary Tree Postorder Traversal - Explanation
Description
You are given the root of an n-ary tree, return the postorder traversal of its nodes' values.
Nary-Tree input serialization is represented in their level order traversal. Each group of children is separated by the null value (See examples)
Example 1:
Input: root = [1,null,3,2,4,null,5,6]
Output: [5,6,3,2,4,1]Example 2:
Input: 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]
Output: [2,6,14,11,7,3,12,8,4,13,9,10,5,1]Constraints:
0 <= number of nodes in the tree <= 10,0000 <= Node.val <= 10,000- The height of the n-ary tree is less than or equal to
1000.
Follow up: Recursive solution is trivial, could you do it iteratively?
Topics
Prerequisites
Before attempting this problem, you should be comfortable with:
- Tree Data Structures - Understanding how N-ary trees differ from binary trees (nodes can have multiple children)
- Recursion - The recursive DFS solution relies on understanding how recursive calls process children before the parent
- Stack - The iterative solution uses a stack to simulate recursion and manage traversal order
1. Depth First Search
Intuition
Postorder traversal means we visit all children of a node before visiting the node itself. For an N-ary tree, this translates to recursively processing each child subtree from left to right, then adding the current node's value to the result. The recursive approach naturally handles this ordering since the node's value is appended only after all recursive calls on its children have completed.
Algorithm
- Create an empty
reslist. - Define a recursive helper function
dfs(node):- If the node is
null, return immediately. - For each
childof the node, recursively calldfs(child). - After processing all children, append the node's value to the
reslist.
- If the node is
- Call
dfs(root)and return thereslist.
"""
# Definition for a Node.
class Node:
def __init__(self, val: Optional[int] = None, children: Optional[List['Node']] = None):
self.val = val
self.children = children
"""
class Solution:
def postorder(self, root: 'Node') -> List[int]:
res = []
def dfs(node):
if not node:
return
for child in node.children:
dfs(child)
res.append(node.val)
dfs(root)
return resTime & Space Complexity
- Time complexity:
- Space complexity: for the recursion stack.
2. Iterative DFS
Intuition
To convert the recursive solution to an iterative one, we use a stack. The key challenge is ensuring we process a node only after all its children have been processed. We achieve this by pushing each node onto the stack twice: once to signal that its children should be explored, and once to signal that it should be added to the result. A visited flag distinguishes between these two cases. When we pop a node that has been visited, we add it to the result. When we pop an unvisited node, we mark it as visited, push it back, then push all its children in reverse order.
Algorithm
- If the root is
null, return an empty list. - Initialize a
stackwith the pair(root, false), wherefalseindicates the node has not beenvisited. - While the
stackis not empty:- Pop a pair
(node, visited). - If
visitedistrue, addnode.valto the result. - Otherwise, push
(node, true)back onto thestack, then push all children in reverse order as(child, false).
- Pop a pair
- Return the result list.
"""
# Definition for a Node.
class Node:
def __init__(self, val: Optional[int] = None, children: Optional[List['Node']] = None):
self.val = val
self.children = children
"""
class Solution:
def postorder(self, root: 'Node') -> List[int]:
res = []
if not root:
return res
stack = [(root, False)]
while stack:
node, visited = stack.pop()
if visited:
res.append(node.val)
else:
stack.append((node, True))
for child in reversed(node.children):
stack.append((child, False))
return resTime & Space Complexity
- Time complexity:
- Space complexity:
Common Pitfalls
Appending Node Value Before Processing Children
In postorder traversal, the node's value must be added to the result after all its children have been processed. A common mistake is appending the node's value before or during the iteration over children. This produces preorder output instead of postorder. Always ensure the res.append(node.val) statement comes after the loop that recursively processes all children.
Forgetting to Reverse Children Order in Iterative Approach
When using an explicit stack for iterative postorder traversal, children must be pushed in reverse order so that the leftmost child is processed first. If you push children in their natural order, the rightmost child will be popped and processed first, resulting in incorrect traversal order. Always iterate through children in reverse when adding them to the stack.
Sign in to join the discussion