431. Encode N-ary Tree to Binary Tree


Problem Explanation

Here we're going to design an algorithm to encode an N-ary tree into a binary tree and then be able to decode it back to the original N-ary tree. An N-ary tree is a tree where each node has no more than N children. Similarly, a binary tree is one where each node has no more than 2 children. There is no restriction on how your encoding or decoding should work, but it must be able to accomplish accurately converting between the two tree types.

As an example: Consider an N-ary tree with N=3. It contains a root node and multiple other nodes, each node might have 0 up to 3 children. If we encode this tree as a binary tree, each node of the original N-ary tree could be represented as a binary tree node, with the node's children represented as a linked list of binary tree nodes in the left child of that node. The sibling nodes (other nodes on the same level) are then represented by the right child of each previous node.

For example, an N-ary tree node 1 with children 2, 3, 4, would be encoded into a binary tree like so: Node 1's children are represented as Node 2 (the first child) being the left child of Node 1, Node 3 being the right child of Node 2, and Node 4 being the right child of Node 3.

Solution Explanation

The provided solution encodes N-ary trees as binary trees by taking each node's children and representing them as a linked list in the binary tree. The first child of each N-ary node becomes the left child in the binary tree and other children become the right child of the previous child node.

Decoding is the reverse process. It involves converting the binary tree back to an N-ary tree. The left child of each binary tree node becomes the first child in the N-ary tree, and the right child of each binary tree node becomes the next sibling in the N-ary tree.

The solution uses a queue data structure to traverse both trees in level order and a similar approach using two while loops in both encoding and decoding methods.

Let's write this solution in different programming languages.


python
from collections import deque

class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children if children else []

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Codec:
    def encode(self, root):
        if not root: return None
        newRoot = TreeNode(root.val)
        queue = deque([(newRoot, root)])

        while queue:
            parent, curr = queue.popleft()
            dummy = head = TreeNode(0)
            for child in curr.children:
                newNode = TreeNode(child.val)
                dummy.right = newNode
                dummy = newNode
                queue.append((newNode, child))
            parent.left = head.right
        return newRoot

    def decode(self, data):
        if not data: return None
        root = Node(data.val)
        queue = deque([(root, data)])

        while queue:
            parent, curr = deque.popleft()
            firstChild = curr.left
            sibling = firstChild
            while sibling:
                newNode = Node(sibling.val)
                parent.children.append(newNode)
                queue.append((newNode, sibling))
                sibling = sibling.right
        return root

java
import java.util.*;

class Node {
    public int val;
    public List<Node> children;

    public Node() {}

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

class TreeNode {
     int val;
     TreeNode left;
     TreeNode right;
     TreeNode(int x) { val = x; }
 }

class Codec {
    public TreeNode encode(Node root) {
        if (root == null) return null;
        TreeNode newRoot = new TreeNode(root.val);
        if (root.children.size() > 0) {
            newRoot.left = encode(root.children.get(0));
        }
        TreeNode sibling = newRoot.left;
        for (int i = 1; i < root.children.size(); ++i) {
            sibling.right = encode(root.children.get(i));
            sibling = sibling.right;
        }
        return newRoot;
    }

    public Node decode(TreeNode root) {
        if (root == null) return null;
        Node newRoot = new Node(root.val, new LinkedList<>());
        TreeNode sibling = root.left;
        while (sibling != null) {
            newRoot.children.add(decode(sibling));
            sibling = sibling.right;
        }
        return newRoot;
    }
}

javascript
function Node(val,children) {
     this.val = val;
     this.children = children;
};

function TreeNode(val, left, right) {
      this.val = (val===undefined ? 0 : val)
      this.left = (left===undefined ? null : left)
      this.right = (right===undefined ? null : right)
};

class Codec {
    encode(root) {
        if (!root) return null;
        let newRoot = new TreeNode(root.val);
        if (root.children.length > 0) {
            newRoot.left = this.encode(root.children[0]);
        } 
        let sibling = newRoot.left;
        for (let i = 1; i < root.children.length; ++i) {
            sibling.right = this.encode(root.children[i]);
            sibling = sibling.right;
        }
        return newRoot;
    }

    decode(root) {
        if (!root) return null;
        let newRoot = new Node(root.val, []);
        let sibling = root.left;
        while (sibling !== null) {
            newRoot.children.push(this.decode(sibling));
            sibling = sibling.right;
        }
        return newRoot;
    }
}

c++
#include <vector>
#include <queue>

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 TreeNode {
public:
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Codec {
public:
    TreeNode* encode(Node* root) {
        if (!root) return NULL;
        TreeNode* newRoot = new TreeNode(root -> val);
        if (!root -> children.empty()) newRoot -> left = encode(root -> children[0]);
        TreeNode* sibling = newRoot -> left;
        for (int i=1; i<root->children.size(); i++) {
            sibling -> right = encode(root -> children[i]);
            sibling = sibling -> right;
        }
        return newRoot;
    }

    Node* decode(TreeNode* root) {
        if (!root) return NULL;
        Node* newRoot = new Node(root -> val, {});
        TreeNode* sibling = root -> left;
        while (sibling != NULL) {
            newRoot -> children.push_back(decode(sibling));
            sibling = sibling -> right;
        }
        return newRoot;
    }
};

The above solutions in Python, Java, and JavaScript, and C++ effectively demonstrate how to solve the problem of encoding and decoding an N-ary tree into and from a binary tree. While each language has its unique syntax and some methods might not be directly transferrable from one language to another, all these solutions hold the same fundamental logic and structure that makes them valid solutions.

In Python, Java, JavaScript, and C++, classes are defined to represent the nodes in the N-ary and binary trees. They also include a Codec class that has encode and decode methods that perform the conversion of trees, and utilize a queue data structure to ease the traversal of nodes.

The encode method starts by checking if the root node exists. If it does not exist, the method returns null, otherwise it creates a new node in the binary tree. It then goes on to convert the children of the current node, if any, into a linked list of binary tree nodes. The first child becomes the left child of the current binary tree node, while the remaining children become the right child of the preceding binary node.

The decode method reverts the encoding process by transforming the linked list of binary tree nodes back into the original N-ary tree. The left child of each binary tree node becomes the first child in the N-ary tree, and all the right children become the next sibling in the N-ary tree.

Despite the differences in syntax and built-in methods among Python, JavaScript, Java, and C++, they all employ the same logic and approach to solving the problem, thus linking these solutions together in their common goal of accurately converting between N-ary and binary trees.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator
Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

Is the following code DFS or BFS?

void search(Node root) {
  if (!root) return;
  visit(root);
  root.visited = true;
  for (Node node in root.adjacent) {
    if (!node.visited) {
      search(node);
    }
  }
}

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More