Before attempting this problem, you should be comfortable with:
To encode an N-ary tree into a binary tree, we need a consistent rule for representing multiple children. The standard approach is the "left-child right-sibling" representation: the first child of an N-ary node becomes the left child of the binary node, and subsequent siblings are chained as right children. Using BFS, we process nodes level by level, building the binary tree structure while maintaining the parent-child relationships through a queue.
Encode:
null, return null.left, rest as right siblings.Decode:
null, return null.left child's right chain to reconstruct all children."""
# Definition for a Node.
class Node(object):
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
"""
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
"""
class Codec:
def encode(self, root):
"""Encodes an n-ary tree to a binary tree.
"""
if not root:
return None
rootNode = TreeNode(root.val)
queue = deque([(rootNode, root)])
while queue:
parent, curr = queue.popleft()
prevBNode = None
headBNode = None
# traverse each child one by one
for child in curr.children:
newBNode = TreeNode(child.val)
if prevBNode:
prevBNode.right = newBNode
else:
headBNode = newBNode
prevBNode = newBNode
queue.append((newBNode, child))
# use the first child in the left node of parent
parent.left = headBNode
return rootNode
def decode(self, data):
"""Decodes your binary tree to an n-ary tree.
"""
if not data:
return None
# should set the default value to [] rather than None,
# otherwise it wont pass the test cases.
rootNode = Node(data.val, [])
queue = deque([(rootNode, data)])
while queue:
parent, curr = queue.popleft()
firstChild = curr.left
sibling = firstChild
while sibling:
# Note: the initial value of the children list should not be None, which is assumed by the online judge.
newNode = Node(sibling.val, [])
parent.children.append(newNode)
queue.append((newNode, sibling))
sibling = sibling.right
return rootNodeTime complexity:
Space complexity:
encode() : .
decode() : .
Since is proportional to in the worst case, we could further generalize the space complexity to .
Where is the number of nodes in the N-ary tree, and is the maximum number of nodes that reside at the same level.
DFS offers a more elegant recursive solution using the same left-child right-sibling encoding. For each N-ary node, we recursively encode its first child and attach it as the left child of the binary node. The remaining children are encoded and linked as right siblings of the first child. Decoding reverses this: we traverse the left child's right chain to rebuild the children list.
Encode:
null, return null.left.right siblings.Decode:
null, return null.left child.right sibling."""
# Definition for a Node.
class Node(object):
def __init__(self, val=None, children=None):
self.val = val
self.children = children
"""
"""
# Definition for a binary tree node.
class TreeNode(object):
def __init__(self, x):
self.val = x
self.left = None
self.right = None
"""
class Codec:
def encode(self, root):
"""Encodes an n-ary tree to a binary tree.
"""
if not root:
return None
rootNode = TreeNode(root.val)
if len(root.children) > 0:
firstChild = root.children[0]
rootNode.left = self.encode(firstChild)
# the parent for the rest of the children
curr = rootNode.left
# encode the rest of the children
for i in range(1, len(root.children)):
curr.right = self.encode(root.children[i])
curr = curr.right
return rootNode
def decode(self, data):
"""Decodes your binary tree to an n-ary tree.
"""
if not data:
return None
rootNode = Node(data.val, [])
curr = data.left
while curr:
rootNode.children.append(self.decode(curr))
curr = curr.right
return rootNodeTime complexity:
Space complexity:
Since is proportional to in the worst case, we could further generalize the space complexity to
Unlike the BFS algorithm, we don't use the queue data structure in the DFS algorithm. However, implicitly the algorithm would consume more space in the function call stack due to the recursive function calls.
And this consumption of call stack space is the main space complexity for our DFS algorithm. As we can see, the size of the call stack at any moment is exactly the number of level where the currently visited node resides, e.g. for the root node (level 0), the recursive call stack is empty.
Where is the number of nodes in the N-ary tree, and is the depth of the N-ary tree.
In the encoding scheme, left points to the first child of the N-ary node, while right links siblings together. A common mistake is reversing these roles or using right for children, which breaks the bidirectional mapping and makes decoding impossible.
When decoding, the N-ary node's children list must be initialized as an empty list, not null or None. Many online judges expect an empty list for leaf nodes, and failing to initialize causes null pointer exceptions when appending children.
Both encode and decode must handle null input and return null. Forgetting this base case causes null pointer exceptions when the root is null, as the algorithm tries to access properties of a non-existent node.
When decoding, you must traverse the entire right-sibling chain starting from the left child. A common mistake is only processing the immediate left child without following the right pointers, which loses all siblings after the first child.