LeetCode 431: Encode N-ary Tree to Binary Tree Solution in Python – A Step-by-Step Guide

Imagine you’ve got a sprawling N-ary tree—like a root node 1 with children 2, 3, and 4, where 3 has its own kids 5 and 6—and your task is to reshape it into a binary tree, where each node has at most two children (left and right). Then, you need to reverse the process to get the original N-ary tree back. For example, you might turn 1’s kids into a chain: 1’s left is 2, 2’s right is 3, 3’s right is 4, and 3’s left drops to 5, with 5’s right to 6. That’s the clever challenge of LeetCode 431: Encode N-ary Tree to Binary Tree, a hard-level problem that’s all about transforming tree structures. Using Python, we’ll tackle it two ways: the Best Solution, a left-child right-sibling encoding that reshapes efficiently, and an Alternative Solution, a serialized string approach that flattens and rebuilds. With examples, code, and a friendly vibe, this guide will help you encode that tree, whether you’re new to coding or leveling up your skills. Let’s reshape those branches and dive in!

What Is LeetCode 431: Encode N-ary Tree to Binary Tree?

Section link icon

In LeetCode 431: Encode N-ary Tree to Binary Tree, you’re given two tasks: 1. Encode: Convert an N-ary tree (where each Node has a value val and a list of children children) into a binary tree (where each TreeNode has val, left, and right). 2. Decode: Convert the binary tree back into the original N-ary tree. An N-ary tree allows any number of children per node, unlike a binary tree’s limit of two. For example, an N-ary tree with root 1, children [2, 3, 4], and 3’s children [5, 6] needs a binary encoding—perhaps 1’s left is 2, 2’s right is 3, 3’s right is 4, and 3’s left is 5 with 5’s right as 6—then decoded back perfectly. The encoding must preserve the structure for accurate reconstruction.

Problem Statement

  • Input:
    • Encode: A Node (root of N-ary tree).
    • Decode: A TreeNode (root of binary tree).
  • Output:
    • Encode: A TreeNode (root of binary tree).
    • Decode: A Node (root of N-ary tree).
  • Rules:
    • Encode N-ary tree into binary tree.
    • Decode binary tree back to original N-ary tree.
    • Use provided Node and TreeNode classes.

Constraints

  • Number of nodes is in range [0, 10⁴].
  • 0 <= Node.val <= 10⁴.
  • Values may not be unique.

Examples

  • Input: [1,null,2,3,4,null,5,6]
    • Encode: Binary tree (e.g., 1.left = 2, 2.right = 3, 3.right = 4, 3.left = 5, 5.right = 6).
    • Decode: Original N-ary tree: 1, children [2, 3, 4], 3’s children [5, 6].
  • Input: [1,null,3,null,2]
    • Encode: 1.left = 3, 3.left = 2.
    • Decode: 1, children [3], 3’s child [2].
  • Input: []
    • Encode/Decode: None.

Understanding the Problem: Reshaping the Tree

Section link icon

To solve LeetCode 431: Encode N-ary Tree to Binary Tree in Python, we need to: 1. Encode: Transform an N-ary tree into a binary tree, preserving all info. 2. Decode: Reverse the process to restore the N-ary tree. A naive idea might be to just dump all children into left—but we’d lose the multi-child structure! We’ll use:

  • Best Solution (Left-Child Right-Sibling Encoding): O(n) time, O(h) space—reshapes efficiently.
  • Alternative Solution (Serialized String Approach): O(n) time, O(n) space—flattens and rebuilds.

Let’s dive into the left-child right-sibling solution with a clear, step-by-step explanation.

Best Solution: Left-Child Right-Sibling Encoding

Section link icon

Why This Is the Best Solution

The left-child right-sibling encoding method is the top pick because it’s efficient—O(n) time for both encode and decode, O(h) space (h = height)—and elegantly maps N-ary children into a binary structure using a standard technique: the first child goes to left, and subsequent siblings chain via right. It decodes by reversing this pattern, collecting siblings into a list. It’s like threading N-ary kids into a binary chain, then unthreading them back into a family!

How It Works

Encode

  • Step 1: For each node:
    • If no children, return a binary TreeNode with val, no kids.
    • If children exist:
      • left = first child (recursively encoded).
      • Chain remaining children via right (siblings).
  • Step 2: Return binary root.

Decode

  • Step 1: Start at binary root.
  • Step 2: For each node:
    • Create N-ary Node with val.
    • Collect children: follow left to first child, then right for siblings.
    • Recurse on each child’s left.
  • Step 3: Return N-ary root.

Why It Works

  • Left-child right-sibling preserves all N-ary info in binary form.
  • Recursive encoding/decoding ensures O(n) time, minimal space.
  • It’s like folding a fan into a stick, then unfolding it back!

Step-by-Step Example

Example: [1,null,2,3,4,null,5,6]

  • N-ary Tree:

1 /|\ 2 3 4 / \ 5 6

  • Encode:
    • Node 1: Children [2, 3, 4].
      • Left = 2 (TreeNode(2)).
      • 2.right = 3 (TreeNode(3)).
      • 3.right = 4 (TreeNode(4)).
      • 3.left = 5 (TreeNode(5)), 5.right = 6 (TreeNode(6)).
    • Binary Tree:

1 / 2 \ 3 / \ 5 4 \ 6

  • Decode:
    • Root 1: Left = 2.
      • Node 2: No left, siblings [3].
      • Node 3: Left = 5, siblings [4], 5’s sibling [6].
    • Result: Original N-ary tree.

Code with Detailed Line-by-Line Explanation

Here’s the Python code, broken down so you can follow every step:

# Definition for a Node.
class Node:
    def __init__(self, val=None, children=None):
        self.val = val
        self.children = children if children is not None else []

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

class Codec:
    def encode(self, root: 'Node') -> 'TreeNode':
        if not root:
            return None

        # Step 1: Create binary root
        binary_root = TreeNode(root.val)

        # Step 2: Encode children
        if root.children:
            # First child to left
            binary_root.left = self.encode(root.children[0])
            # Chain siblings to right
            curr = binary_root.left
            for child in root.children[1:]:
                curr.right = self.encode(child)
                curr = curr.right

        return binary_root

    def decode(self, root: 'TreeNode') -> 'Node':
        if not root:
            return None

        # Step 1: Create N-ary root
        nary_root = Node(root.val)

        # Step 2: Decode children
        if root.left:
            # First child from left
            nary_root.children.append(self.decode(root.left))
            # Siblings from right chain
            curr = root.left.right
            while curr:
                nary_root.children.append(self.decode(curr))
                curr = curr.right

        return nary_root
  • Line 2-6: N-ary Node class (given):
    • val, children (list of kids).
  • Line 9-13: Binary TreeNode class (given):
    • val, left, right.
  • Encode:
    • Line 18-20: Handle empty root, return None.
    • Line 23: Create binary node with val.
    • Line 26-32: Encode children:
      • Line 27-28: If kids, left = first child (recursed).
      • Line 30-32: Chain others via right (siblings).
    • Line 34: Return binary root.
  • Decode:
    • Line 38-40: Handle empty root, return None.
    • Line 43: Create N-ary node with val.
    • Line 46-52: Decode children:
      • Line 47-48: If left, append first child (recursed).
      • Line 50-52: Follow right chain, append siblings.
    • Line 54: Return N-ary root.
  • Time Complexity: O(n)—each node processed once.
  • Space Complexity: O(h)—recursion stack, h = height.

This is like folding an N-ary fan into a binary stick and unfolding it back!

Alternative Solution: Serialized String Approach

Section link icon

Why an Alternative Approach?

The serialized string approach first flattens the N-ary tree into a string (e.g., preorder with child counts), then rebuilds it as a binary tree, and reverses the process. It’s O(n) time and O(n) space—explicit but memory-heavy due to string storage. It’s like writing the tree as a message, then parsing it into binary form!

How It Works

Encode

  • Serialize N-ary tree to string (e.g., "1,3,2,0,3,2,5,0,6,0,4,0").
  • Parse string into binary tree with values and structure.

Decode

  • Serialize binary tree back to string.
  • Reconstruct N-ary tree from string.

Step-by-Step Example

Example: [1,null,2,3,4,null,5,6]

  • Serialize: "1,3,2,0,3,2,5,0,6,0,4,0".
  • Encode: Binary tree (e.g., store string as nodes or parse directly).
  • Decode: Reverse to N-ary tree.

Code for Serialized Approach (Simplified)

class Codec:
    def serialize_nary(self, root):
        if not root:
            return ""
        result = [str(root.val), str(len(root.children))]
        for child in root.children:
            result.extend(self.serialize_nary(child))
        return ",".join(result)

    def encode(self, root: 'Node') -> 'TreeNode':
        if not root:
            return None
        serialized = self.serialize_nary(root)
        nodes = serialized.split(",")
        def build_binary(idx):
            if idx >= len(nodes):
                return None, idx
            node = TreeNode(int(nodes[idx]))
            idx += 1
            child_count = int(nodes[idx])
            idx += 1
            if child_count > 0:
                node.left, idx = build_binary(idx)
                curr = node.left
                for _ in range(child_count - 1):
                    curr.right, idx = build_binary(idx)
                    curr = curr.right
            return node, idx
        binary_root, _ = build_binary(0)
        return binary_root

    def decode(self, root: 'TreeNode') -> 'Node':
        if not root:
            return None
        # Simplified: assumes same serialization
        serialized = self.serialize_binary(root)
        nodes = serialized.split(",")
        def build_nary(idx):
            if idx >= len(nodes):
                return None, idx
            node = Node(int(nodes[idx]))
            idx += 1
            child_count = int(nodes[idx])
            idx += 1
            for _ in range(child_count):
                child, idx = build_nary(idx)
                node.children.append(child)
            return node, idx
        nary_root, _ = build_nary(0)
        return nary_root

    def serialize_binary(self, root):
        if not root:
            return ""
        result = [str(root.val), "1"]  # Simplified child count
        if root.left:
            result.extend(self.serialize_binary(root.left))
        if root.right:
            result.extend(self.serialize_binary(root.right))
        return ",".join(result)
  • Time Complexity: O(n)—each node processed.
  • Space Complexity: O(n)—string storage.

It’s a string-based reshaper!

Comparing the Two Solutions

Section link icon
  • Left-Child Right-Sibling (Best):
    • Pros: O(n), O(h), direct and lean.
    • Cons: Structural mapping.
  • Serialized String (Alternative):
    • Pros: O(n), O(n), explicit string.
    • Cons: Extra space, parsing.

Left-child right-sibling wins for efficiency.

Additional Examples and Edge Cases

Section link icon
  • []: None.
  • [1]: 1 (binary: 1).
  • [1,null,2]: 1.left = 2.

Left-child handles all.

Complexity Breakdown

Section link icon
  • Left-Child: Time O(n), Space O(h).
  • Serialized: Time O(n), Space O(n).

Left-child is optimal.

Key Takeaways

Section link icon
  • Left-Child: Chain it smart!
  • Serialized: String it out!
  • Trees: Structures twist.
  • Python Tip: Recursion rocks—see [Python Basics](/python/basics).

Final Thoughts: Encode That Tree

Section link icon

LeetCode 431: Encode N-ary Tree to Binary Tree in Python is a tree-reshaping quest. Left-child right-sibling encoding threads it fast, while serialized string flattens it steady. Want more tree fun? Try LeetCode 426: Convert Binary Search Tree to Sorted Doubly Linked List or LeetCode 589: N-ary Tree Preorder Traversal. Ready to reshape? Head to Solve LeetCode 431 on LeetCode and encode that tree today!