Leetcode 589. N-ary Tree Preorder Traversal

Problem explanation:

The problem is about finding the preorder traversal of an n-ary tree. Pre-order traversal is a type of depth-first search where the search traverses the structure from the root to the farthest leaf node. This kind of traversal visits each node before its children. For an n-ary tree (where each node can have n children), the pre-order traversal follows a root-children pattern. For example, if we are given a 3-ary tree:

1
2
3     1
4   / | \
5  3  2  4
6 / \
75   6   

The pre-order traversal will be [1,3,5,6,2,4]

Solution approach:

In the iterative solution to this problem, we will use a data structure called a stack. A stack is a Last-In-First-Out (LIFO) data type, which allows us to store the nodes of our tree in a specific order so that we can traverse the tree.

The basic approach is as follows:

  1. If the root is null, return an empty list
  2. Create a stack and put the root into it
  3. While the stack is not empty:
    1. Pop a node from the stack,
    2. Record its value in your output list
    3. Push its children into the stack (from right to left so that you can visit all left nodes first as per pre-order rule: root->left->right)

Time complexity of this approach is O(n) where n is the number of nodes because each node is pushed and popped exactly once. And the space complexity is O(n) for storing the nodes in the stack.

Python 3 solution:

1
2python
3class Node:
4    def __init__(self, val=None, children=None):
5        self.val = val
6        self.children = children
7
8class Solution:
9    def preorder(self, root):
10        res = []
11        if root is None:
12            return res
13
14        stack = [root]
15        while stack:
16            root = stack.pop()
17            res.append(root.val)
18            stack.extend(root.children[::-1])
19
20        return res

Java solution:

1
2java
3import java.util.*;
4
5class Node {
6    public int val;
7    public List<Node> children;
8
9    public Node() {}
10
11    public Node(int _val) {
12        val = _val;
13    }
14
15    public Node(int _val, List<Node> _children) {
16        val = _val;
17        children = _children;
18    }
19}
20
21
22class Solution {
23    public List<Integer> preorder(Node root) {
24        List<Integer> list = new ArrayList<>();
25        if (root == null) return list;
26
27        Stack<Node> stack = new Stack<>();
28        stack.add(root);
29
30        while (!stack.empty()) {
31            root = stack.pop();
32            list.add(root.val);
33            for (int i = root.children.size() - 1; i >= 0; i--)
34                stack.add(root.children.get(i));
35        }
36
37        return list;
38    }
39}

JavaScript solution:

1
2javascript
3var preorder = function(root) {
4    let result = [];
5    if (root === null) {
6        return result;
7    }
8
9    let stack = [root];
10    while (stack.length) {
11        let node = stack.pop();
12        result.push(node.val);
13        for (let i = node.children.length - 1; i >= 0; i--) {
14            stack.push(node.children[i]);
15        }
16    }
17
18    return result;
19};

C++ solution:

1
2cpp
3#include<stack>
4#include<vector>
5using namespace std;
6
7class Node {
8public:
9    int val;
10    vector<Node*> children;
11
12    Node() {}
13
14    Node(int _val) {
15        val = _val;
16    }
17
18    Node(int _val, vector<Node*> _children) {
19        val = _val;
20        children = _children;
21    }
22};
23
24class Solution {
25public:
26    vector<int> preorder(Node* root) {
27        vector<int> res;
28        if (root == NULL)
29            return res;
30
31        stack<Node*> nodeStack;
32        nodeStack.push(root);
33
34        while (!nodeStack.empty()) {
35            Node* node = nodeStack.top();
36            nodeStack.pop();
37            res.push_back(node->val);
38
39            for (int i = node->children.size() - 1; i >= 0; i--)
40                nodeStack.push(node->children[i]);
41        }
42
43        return res;
44    }
45};

C# solution:

1
2csharp
3using System.Collections.Generic;
4
5public class Node {
6    public int val;
7    public IList<Node> children;
8
9    public Node() {}
10    public Node(int _val,IList<Node> _children) {
11        val = _val;
12        children =_children;
13    }
14}
15
16public class Solution {
17    public IList<int> Preorder(Node root) {
18        List<int> list = new List<int>();
19        if (root == null)
20            return list;
21
22        Stack<Node> stack = new Stack<Node>();
23        stack.Push(root);
24
25        while (stack.Count > 0) {
26            root = stack.Pop();
27            list.Add(root.val);
28            for (int i = root.children.Count - 1; i >= 0; i--)
29                stack.Push(root.children[i]);
30        }
31
32        return list;
33    }
34}

With the solutions provided above, the pre-order traversal of a tree with n nodes can be implemented in Python, Java, JavaScript, C++ and C#. All of these solutions use a similar approach of storing tree nodes in a stack and recording their values in an output list when they are popped from the stack.

The stack stores the nodes in LIFO order, ensuring that each node's left branches are visited before the right branches. This follows the rule of pre-order traversal (root-left-right). The solutions take care to push child nodes onto the stack from right to left so that when they are popped, the left-most child node is visited first.

The solutions also consider the case where the root node is null and immediately return an empty list. This provides a smooth operation in the scenario of an empty tree, avoiding any null reference exceptions and ensuring correct output.

So, whether you are working with a large tree structure or a simple binary tree, these solutions will help you traverse the tree in the pre-order way. Not only are these solutions efficient, but they also clearly showcase the use of the stack data structure for traversal problems in tree data structures. One of the major advantages of utilizing stacks in tree traversals is that it solves space-related issues and provides a simple approach without the use of recursion.

In conclusion, given the root node of an n-ary tree data structure, these solutions using Python, Java, JavaScript, C++, and C# will return a list of the tree’s nodes in pre-order traversal order, correctly and efficiently following the depth-first search (DFS) algorithm.

And thus, we have covered ways on how to traverse an n-ary tree Preorder manner in multiple popular languages. Future posts would cover the other ways to traverse a tree, such as Post-order, In-order, Level order etc. Until then, continue exploring and coding!


Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.


TA 👨‍🏫