N-ary Tree Postorder Traversal

EASY

Description

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:

  • The number of nodes in the tree is in the range [0, 104].
  • 0 <= Node.val <= 104
  • 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?


Approaches

Checkout 2 different approaches to solve N-ary Tree Postorder Traversal. Click on different approaches to view the approach and algorithm in detail.

Iterative Approach using a Stack

An iterative solution avoids recursion and the risk of stack overflow. A common and elegant iterative technique for postorder traversal involves using a single stack and modifying the preorder traversal logic. The standard preorder traversal is (Root, Left, Right). We can modify it to (Root, Right, Left) and then reverse the result to get (Left, Right, Root), which is the postorder traversal.

Algorithm

  • Initialize an empty LinkedList<Integer> named result and an empty Stack<Node> named stack.
  • If root is null, return the empty result.
  • Push the root node onto the stack.
  • Loop while the stack is not empty:
  • Pop a node, `current`, from the `stack`.
    
  • Add `current.val` to the *front* of the `result` list.
    
  • Iterate through the children of `current` from left to right and push each `child` onto the `stack`.
    
  • Return the result list.

For an N-ary tree, the modified preorder traversal becomes (Root, Last Child, ..., First Child).

  • We initialize a stack and push the root node onto it.
  • We also initialize a LinkedList for our result. Using a LinkedList allows for efficient O(1) additions to the front.
  • We loop as long as the stack is not empty. In each iteration:
    1. We pop a node from the stack.
    2. We add this node's value to the front of our result list. This is the key step that achieves the reversal.
    3. We then iterate through the children of the popped node (from left to right) and push them onto the stack. Because the stack is a LIFO (Last-In, First-Out) structure, the last child pushed (the rightmost one) will be on top and will be processed next.
  • This process effectively traverses the tree in the order of Root, Child_N, ..., Child_1 and builds the result list in reverse, yielding the correct postorder sequence Child_1, ..., Child_N, Root.
/*
// Definition for a Node.
class Node {
    public int val;
    public List<Node> children;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, List<Node> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
    public List<Integer> postorder(Node root) {
        LinkedList<Integer> result = new LinkedList<>();
        if (root == null) {
            return result;
        }

        Stack<Node> stack = new Stack<>();
        stack.push(root);

        while (!stack.isEmpty()) {
            Node node = stack.pop();
            // Add to the front of the list
            result.addFirst(node.val);

            // Push children from left to right, so they are processed from right to left
            for (Node child : node.children) {
                stack.push(child);
            }
        }
        return result;
    }
}

If using an ArrayList, you would add to the end and then reverse the entire list once at the end using Collections.reverse(result). Adding to the front of a LinkedList is generally more efficient.

Complexity Analysis

Time Complexity: O(N), where N is the total number of nodes. Each node is pushed onto and popped from the stack exactly once.Space Complexity: O(W), where W is the maximum width of the tree. In the worst case of a complete N-ary tree, the last level can contain roughly O(N) nodes. Therefore, the worst-case space complexity is O(N).

Pros and Cons

Pros:
  • Avoids recursion, eliminating the risk of stack overflow.
  • Can be slightly more memory efficient by using heap memory (for the stack) instead of the call stack.
Cons:
  • The logic is less direct and intuitive compared to the recursive solution.

Code Solutions

Checking out 3 solutions in different languages for N-ary Tree Postorder Traversal. Click on different languages to view the code.

/* // Definition for a Node. class Node { public int val; public List<Node> children; public Node() {} public Node(int _val) { val = _val; } public Node(int _val, List<Node> _children) { val = _val; children = _children; } }; */ class Solution { public List < Integer > postorder ( Node root ) { LinkedList < Integer > ans = new LinkedList <>(); if ( root == null ) { return ans ; } Deque < Node > stk = new ArrayDeque <>(); stk . offer ( root ); while (! stk . isEmpty ()) { root = stk . pollLast (); ans . addFirst ( root . val ); for ( Node child : root . children ) { stk . offer ( child ); } } return ans ; } }

Video Solution

Watch the video walkthrough for N-ary Tree Postorder Traversal



Algorithms:

Depth-First Search

Data Structures:

StackTree

Subscribe to Scale Engineer newsletter

Learn about System Design, Software Engineering, and interview experiences every week.

No spam, unsubscribe at any time.