Merge and Serialize N-ary Trees
LinkedInSoftware Engineer · Technical ScreenLast updated
Tests recursive tree manipulation, immutable merging semantics, and robust string serialization/deserialization with input validation.
Problem Statement
You are building a hierarchical configuration synchronizer. Configurations are represented as N-ary trees where each node contains:
key: a non-empty string identifier unique among siblingsval: an integer valuechildren: a list of childNodeinstances
You need to implement three functions:
-
merge_trees(t1: Optional[Node], t2: Optional[Node]) -> Optional[Node]: Merges two trees into a new tree without mutatingt1ort2.- If one tree is
None, return a deep copy of the other. - If both trees are non-empty, their root keys must match. If root keys differ, raise a
ValueError. - For matching nodes, the merged node's
valist1.val + t2.val. - Merge children recursively: children with matching keys are merged; children present in only one tree are copied.
- To ensure deterministic output, each node's
childrenmust be sorted alphabetically bykey.
- If one tree is
-
serialize(root: Optional[Node]) -> str: Encodes the tree into a deterministic string representation. Return"#"forNone. For a valid node, format it askey:val[child1,child2,...]where children are recursively serialized and sorted alphabetically by key. -
deserialize(data: str) -> Optional[Node]: Decodes the serialized string back into an N-ary tree. RaisesValueErrorifdatais malformed (e.g., mismatched brackets, invalid integers, duplicate sibling keys, or trailing characters).
Interface
from typing import List, Optional
class Node:
def __init__(self, key: str, val: int, children: Optional[List['Node']] = None):
self.key = key
self.val = val
self.children = children if children is not None else []
def merge_trees(t1: Optional[Node], t2: Optional[Node]) -> Optional[Node]:
pass
def serialize(root: Optional[Node]) -> str:
pass
def deserialize(data: str) -> Optional[Node]:
pass
Examples
Example 1
# t1: root:5 [a:2, b:3]
# t2: root:10 [b:4, c:1]
merged = merge_trees(t1, t2)
# merged: root:15 [a:2, b:7, c:1]
s = serialize(merged)
# Output: "root:15[a:2[],b:7[],c:1[]]"
node = deserialize(s)
# Round-trip check: serialize(node) == s
Example 2
t1 = Node("A", 1)
t2 = Node("B", 2)
merge_trees(t1, t2) # Raises ValueError: root keys do not match
Constraints
- Number of nodes in any tree:
0 <= N <= 10^4 - Node key: alphanumeric string,
1 <= len(key) <= 32 - Node val:
-10^6 <= val <= 10^6 - Maximum tree depth:
<= 1000
Hints
Hint 1
For merging without mutation, use a recursive helper that constructs new Node objects, grouping children by their keys via a hash map or two-pointer merge over sorted child lists.
Hint 2
For serialization, recursion produces a clean canonical string; make sure you process children in sorted key order.
Hint 3
For deserialization, use an index pointer or parser token stream to parse `key`, `:`, `val`, and handle nested bracketed children with explicit validation checks.
Follow-up questions
- How would you handle merge conflicts if two nodes have metadata requiring distinct resolution strategies (e.g., last-write-wins vs. max value) instead of summation?
- If trees exceed memory limits and must be streamed from disk, how would you redesign the merge and serialization pipeline?
- How can you avoid recursion depth limits when dealing with degenerate trees of depth up to 10^5?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.