Serialization encodes a binary tree as a string; deserialization reconstructs the exact tree from that string. Implement a serialize and a deserialize so that deserialize(serialize(root)) returns a tree identical to the original.
Here you're given the root; return deserialize(serialize(root)) — the reconstructed tree, which the grader compares against the input. The tree is given/returned in level-order (breadth-first), using null for missing children.
Input: root = [1, 2, 3, null, null, 4, 5] Output: [1, 2, 3, null, null, 4, 5] serialize then deserialize reproduces the same tree.
Input: root = [] Output: [] An empty tree round-trips to empty.
- The number of nodes is in the range [0, 10^4] - -1000 <= Node.val <= 1000
The whole trick is null markers. A traversal that also records the empty children uniquely encodes a tree — and reading that same stream back, markers and all, rebuilds it exactly. No second traversal needed, because the null markers restore the structure the inorder split would otherwise provide.
“How do you encode empty children?”
With a sentinel token (like #) so structure is preserved.
“Preorder or level-order?”
Either works, as long as serialize and deserialize agree.
I do a preorder walk and write a marker for every null, which uniquely encodes the tree.
To deserialize I read the same stream: a value creates a node whose left then right subtrees I build recursively; a marker returns null.
Worked example — tree [1, 2, 3, null, null, 4, 5], preorder codec
serialize: 1,2,#,#,3,4,#,#,5,#,# deserialize: 1 -> left(2 -> #,#) -> right(3 -> left(4 -> #,#), right(5 -> #,#)) reconstructed tree == original
Recording empty children restores the structure, so you don't need a second traversal.
The reader consumes tokens in exactly the order the writer produced them.
Both are O(n); preorder is a clean recursion, level-order a clean queue loop.
| Level-order (BFS) codec | Preorder (DFS) codec | |
|---|---|---|
| Idea | Queue; sentinel for null children | Recursion; sentinel for null children |
| Time | O(n) | O(n) |
| Space | O(n) | O(n) |
Both preserve the tree exactly. Full code is in the Approaches selector below.
Key takeaway
Serialize with a traversal that writes a null-marker for every empty child; deserialize by reading the same stream back. Preorder or level-order, both O(n).
serialize(node): if null: emit "#"; else emit val; serialize(left); serialize(right) deserialize(): v = next; if v=="#": return null; node=v; node.left=deserialize(); node.right=deserialize()