InterviewPrepKit

Home / Coding / Trees

Serialize and Deserialize Binary Tree

hard Original ↗
Solving tips
  • Key insight: pick one fixed traversal (preorder DFS) and emit an explicit null marker like '#' so the shape is recoverable from a single stream.
  • Deserialize by consuming tokens in the exact order you produced them: read a token, return None on '#', else build node then recurse left then right.
  • Use a real delimiter (comma) between tokens since values are negative and multi-digit; both directions are O(n) time and O(n) space.
  • Pitfalls: omitting null markers makes the encoding ambiguous, and a 10^4-node chain can blow CPython's recursion limit (raise it or use the BFS/queue variant).

Problem

Design a codec that converts a binary tree into a single string (serialize) and reconstructs the exact same tree from that string (deserialize). You are free to choose any string format you like — the only requirement is that deserialize(serialize(root)) returns a tree identical in structure and values to the original.

Implement a class:

  • serialize(root) — takes the root of a binary tree, returns a string.
  • deserialize(data) — takes a string previously produced by serialize, returns the rebuilt tree’s root.

Examples

Example 1

    1
   / \
  2   3
     / \
    4   5

Input: root = [1,2,3,null,null,4,5] → Output: [1,2,3,null,null,4,5] One valid encoding is the preorder string "1,2,#,#,3,4,#,#,5,#,#"; decoding it reproduces the tree exactly.

Example 2

Input: root = [] → Output: [] The empty tree must round-trip too — e.g. encode it as "#" (or "") and decode that back to None.

Example 3

  1
 /
2

Input: root = [1,2] → Output: [1,2] A left-only child shows why nulls must be recorded: without a marker, "1,2" can’t tell a left child from a right child.

Constraints

  • The tree has between 0 and 10⁴ nodes — both directions should run in O(n) and the string should be O(n) characters.
  • -1000 <= Node.val <= 1000 — values can be negative and multi-digit, so you need a real delimiter between tokens.

Think about it first

Hint 1 A plain traversal (preorder, level order, …) lists the values but loses the shape — many trees share the same preorder. What extra tokens could you emit so that the shape is recoverable from a single traversal?
Hint 2 Write out **null children explicitly** (say, as `"#"`). A preorder listing that includes every null uniquely determines the tree: the first token is the root, and the rest splits unambiguously into the left subtree's encoding followed by the right's.
Hint 3 Deserialize by consuming tokens in the same order you produced them. Preorder: take the next token; if it's `"#"` return `None`, otherwise make the node, then recursively build its left subtree, then its right. Level order works the same way with a queue instead of recursion.
Your workspace Not runnable by design — this is your interview scratchpad. Saved on this device.