AlgoMaster Logo

Serialize and Deserialize Binary Tree

Last Updated: March 29, 2026

hard
5 min read

Understanding the Problem

We need to convert a binary tree into a string (serialize) and then reconstruct the exact same tree from that string (deserialize). The critical word here is "exact." We don't just need a tree with the same values, we need the same structure. Left children must stay on the left, right children on the right, and null children must be preserved.

Why is this harder than it sounds? Consider two different trees that produce the same inorder traversal. If our serialization only captures values without structural information, we can't tell them apart during deserialization. So we need to encode not just the node values but also where the nulls are, because null positions define the tree's shape.

The key insight: if we record null markers (like "null" or "#") during traversal, we capture the complete structure. A preorder traversal with null markers uniquely defines a binary tree, and so does a level-order (BFS) traversal with null markers.

Key Constraints:

  • 0 <= number of nodes <= 10^4 — The tree can have up to 10,000 nodes. We need an approach that handles this efficiently, but even O(n^2) would work within time limits. The real challenge is correctness of the serialization format.
  • -1000 <= Node.val <= 1000 — Node values can be negative. Our parsing logic must handle negative signs correctly (e.g., "-1000" is a valid value, not a delimiter followed by "1000").
  • The tree can be empty (0 nodes). Serialize and deserialize must handle null root gracefully.

Approach 1: DFS (Preorder Traversal)

Intuition

The most natural way to think about this: walk the tree in some order, write down what you see, and include markers for "nothing here." Preorder traversal (root, left, right) is the simplest choice because we process the root first, which makes reconstruction straightforward.

Here's the key insight that makes preorder work: if we record null children explicitly, the serialized string contains enough information to reconstruct the tree without any ambiguity. When we later read the string back, we know that the first token is the root, the tokens that follow describe the left subtree (terminated by null markers), and whatever comes after that describes the right subtree.

For serialization, we do a standard preorder DFS. At each node, we append its value. When we hit a null child, we append a special marker like "N". We separate tokens with commas.

For deserialization, we split the string into tokens and consume them one by one. We use a recursive function that reads the next token: if it's "N", return null. Otherwise, create a node with that value, then recursively build its left subtree (which consumes the next chunk of tokens) and its right subtree (which consumes the chunk after that).

Algorithm

Serialize:

  1. If the current node is null, append "N" to the result and return.
  2. Append the node's value to the result.
  3. Recursively serialize the left subtree.
  4. Recursively serialize the right subtree.
  5. Join all values with commas to form the final string.

Deserialize:

  1. Split the serialized string by commas into a list of tokens.
  2. Maintain an index (or use a queue/iterator) to track which token to process next.
  3. Read the next token. If it is "N", return null.
  4. Create a new tree node with the token's integer value.
  5. Recursively build the left child (this advances the index through the left subtree's tokens).
  6. Recursively build the right child (this advances the index through the right subtree's tokens).
  7. Return the constructed node.

Example Walkthrough

1Start preorder DFS at root (1). Serialize: "1"
1visit2345
1/8
1Deserialize: read token[0]="1", create root
0
1
idx
1
2
2
N
3
N
4
3
5
4
6
N
7
N
8
5
9
N
10
N
1/8

Code

The DFS approach is already O(n) in both time and space, which is optimal. But what if we want an iterative solution that avoids deep recursion stacks? A skewed tree with 10,000 nodes would cause 10,000 recursive calls. BFS naturally avoids this by using a queue instead of the call stack.

Approach 2: BFS (Level-Order Traversal)

Intuition

Instead of traversing depth-first, we can serialize the tree level by level using BFS. This is actually how LeetCode itself represents binary trees in its input format: [1,2,3,null,null,4,5].

The idea is straightforward. We use a queue to visit nodes level by level. For each node we dequeue, we append its value and enqueue its children. If a child is null, we append a null marker but don't enqueue anything for it (null nodes have no children to process).

For deserialization, we reverse the process. The first token is the root. We put it in a queue. Then, for each node we dequeue, the next two tokens in the string are its left and right children. If a token is "N", the child is null. Otherwise, we create a node and enqueue it so its children get processed later.

This approach is iterative, so it avoids the potential stack overflow issue with very deep trees.

Algorithm

Serialize:

  1. If root is null, return an empty string.
  2. Initialize a queue with the root node.
  3. While the queue is not empty, dequeue a node.
  4. If the node is null, append "N" to the result.
  5. If the node is not null, append its value and enqueue its left and right children (even if they're null).
  6. Join all values with commas.

Deserialize:

  1. If the string is empty, return null.
  2. Split the string by commas into tokens.
  3. Create the root from the first token and add it to a queue.
  4. Starting from the second token, process tokens in pairs (left child, right child) for each node dequeued.
  5. For each token: if "N", set child to null. Otherwise, create a node, set it as child, and enqueue it.
  6. Return the root.

Example Walkthrough

1BFS serialize: dequeue root (1), enqueue children [2, 3]
1dequeue2345
1/8
1Queue starts with root. Dequeue 1, enqueue children 2 and 3
Front
1
Rear
1/8

Code