Meta — Serialize and Deserialize Binary Tree (BFS + Preorder DFS)

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Problem Statement

Design an algorithm to serialize (encode) a binary tree to a single string and deserialize (decode) that string back to the original tree structure.

Constraints:

  • Number of nodes in tree: 0 to 10^4
  • Node values: -1000 to 1000
  • The encoded string must be valid for any binary tree (not just BST)
Input:  root = [1,2,3,null,null,4,5]
Output: "1,2,3,null,null,4,5" (then reconstruct same tree)
Input:  root = []
Output: "" (empty tree)

Why This Problem Matters

Serialize and Deserialize Binary Tree (LeetCode 297) is Meta's most-asked tree problem and appears in nearly every Meta onsite loop. It tests a fundamental systems skill: converting complex in-memory structures to a portable format and back — the exact operation behind JSON serialization, database storage of tree indexes, and distributed computing task graphs.

Meta interviewers love this problem because it requires you to think about null representation (how do you know where a subtree ends?), traversal choice (BFS vs DFS and the tradeoffs), and error handling during parsing. Engineers who have never thought about encoding schemes will struggle, while candidates who understand tree traversals deeply can solve it in minutes.

Google and Amazon also ask variants: serialize an N-ary tree, serialize a graph, or encode a trie. Mastering the binary tree version gives you the mental model for all of them.

The Core Insight

For DFS preorder: visit root, then recurse left, then right. Null nodes become the literal string "null". To deserialize, consume tokens one by one using an iterator — when you see "null" you return None, otherwise you create a node and recurse for left then right children.

For BFS: process level by level, appending "null" for missing children but never enqueueing them. Deserialization reads tokens left to right, only enqueueing non-null nodes to assign their children.

The DFS approach has cleaner recursive code. The BFS approach produces output identical to LeetCode's tree representation.

Visual Dry Run

Tree:

    1
   / \
  2   3
     / \
    4   5
StepActionResult
Preorder: visit 1append "1"["1"]
Go left to 2append "2"["1","2"]
2's left nullappend "null"["1","2","null"]
2's right nullappend "null"["1","2","null","null"]
Go right to 3append "3"[...,"3"]
3's left = 4append "4","null","null"[...,"4","null","null"]
3's right = 5append "5","null","null"[...,"5","null","null"]

Final: "1,2,null,null,3,4,null,null,5,null,null"

Solution (Optimal)

class Codec:
    def serialize(self, root) -> str:
        res = []
        def dfs(node):
            if not node:
                res.append('null')
                return
            res.append(str(node.val))
            dfs(node.left)
            dfs(node.right)
        dfs(root)
        return ','.join(res)
 
    def deserialize(self, data: str):
        vals = iter(data.split(','))
        def dfs():
            val = next(vals)
            if val == 'null':
                return None
            node = TreeNode(int(val))
            node.left = dfs()
            node.right = dfs()
            return node
        return dfs()
const serialize = (root) => {
    const res = [];
    const dfs = (node) => {
        if (!node) { res.push('null'); return; }
        res.push(String(node.val));
        dfs(node.left);
        dfs(node.right);
    };
    dfs(root);
    return res.join(',');
};
 
const deserialize = (data) => {
    const vals = data.split(',');
    let i = 0;
    const dfs = () => {
        if (vals[i] === 'null') { i++; return null; }
        const node = { val: Number(vals[i++]), left: null, right: null };
        node.left = dfs();
        node.right = dfs();
        return node;
    };
    return dfs();
};

Time: O(N) — visit each node exactly once in both directions Space: O(N) — output string length proportional to nodes; recursion stack O(H) where H is height

Common Mistakes

  • Using BFS serialize with DFS deserialize (or mixing traversal orders) — they must match
  • Forgetting null markers — without them you cannot reconstruct a unique tree
  • Not handling the empty tree case (root is null)
  • Using a space delimiter then splitting on commas — mismatched delimiters break parsing
  • Appending commas inconsistently — trailing comma causes an empty token on split

Interview Tips

  • Start by explaining both BFS and DFS approaches, then pick one and implement it fully
  • The iterator pattern for deserialize (iter() + next()) is cleaner than index tracking
  • Mention that BST serialization can skip null markers (unique structure from values) if asked why we need "null"
  • If asked about production use, mention Protocol Buffers or MessagePack as real alternatives
  • The follow-up to N-ary trees requires pushing children in reverse for DFS; BFS works the same

Follow-up Questions

  • How would you serialize an N-ary tree? — Same idea, but record child count before each node's children
  • How would you handle very deep trees to avoid stack overflow? — Convert DFS to iterative with explicit stack
  • Can you serialize without null markers? — Only if it is a BST; rely on inorder + preorder reconstruction
  • What format is most space-efficient? — Use binary encoding (4 bytes per int) instead of ASCII strings
  • How does this relate to expression trees? — Same preorder encoding; operators as internal nodes

Key Takeaways

  • Preorder DFS with null markers produces a unique encoding for any binary tree
  • The iterator pattern for deserialization avoids index bookkeeping and is cleaner in interviews
  • Both serialize and deserialize run in O(N) time — every node visited exactly once
  • Null markers are mandatory for general binary trees; BST uniqueness allows omitting them
  • Meta asks this to verify you understand the relationship between traversal order and reconstruction
  • The same approach works for N-ary trees and expression trees with minor modifications
  • BFS encoding matches LeetCode's native tree format; DFS encoding is simpler to implement recursively

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading