297. Serialize and Deserialize Binary Tree
hardAsked at HubSpotHubSpot asks Serialize and Deserialize Binary Tree to test OOP design instincts alongside algorithmic thinking — you must design a codec that faithfully round-trips any tree structure, mirroring how their backend engineers design data serialization schemas for tree-structured CRM objects.
By Alex Chen, Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in HubSpot loops.
- Glassdoor (2026-Q1)— HubSpot SWE senior candidates report Serialize/Deserialize Binary Tree as a design-in-coding hard problem in onsite rounds.
- Blind (2025-11)— Multiple HubSpot threads list this problem as a test of both tree traversal fluency and clean API design.
Problem
Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure. Implement the Codec class with serialize(root) and deserialize(data) methods.
Constraints
The number of nodes in the tree is in the range [0, 10^4].-1000 <= Node.val <= 1000The input/output format is not specified — you choose the encoding.
Examples
Example 1
root = [1,2,3,null,null,4,5]serialize → '1,2,null,null,3,4,null,null,5,null,null' (preorder); deserialize → original treeExplanation: Preorder traversal with explicit null markers faithfully encodes all structural information including the positions of null children.
Approaches
1. Preorder DFS with null markers
Serialize using preorder traversal (root, left, right). Represent null children as 'null' tokens. Separate all tokens with commas. Deserialize by consuming tokens from a pointer/queue, recursively building the tree in preorder.
- Time
- O(n) serialize and deserialize
- Space
- O(n) string + O(h) call stack
class Codec {
serialize(root) {
const parts = [];
function dfs(node) {
if (node === null) { parts.push('null'); return; }
parts.push(String(node.val));
dfs(node.left);
dfs(node.right);
}
dfs(root);
return parts.join(',');
}
deserialize(data) {
const tokens = data.split(',');
let idx = 0;
function build() {
if (tokens[idx] === 'null') { idx++; return null; }
const node = new TreeNode(parseInt(tokens[idx++]));
node.left = build();
node.right = build();
return node;
}
return build();
}
}Tradeoff: Clean, O(n) both directions. Preorder with null markers uniquely encodes any binary tree — unlike inorder alone, which is ambiguous without a second traversal. The shared idx (or a pointer object in Java) is the key to stateful token consumption during deserialization.
2. BFS level-order
Serialize using BFS, emitting 'null' for missing children. Deserialize by BFS-reconstructing the tree, assigning left and right children from the token stream to each dequeued node.
- Time
- O(n)
- Space
- O(n) queue
class Codec {
serialize(root) {
if (!root) return 'null';
const queue = [root];
const parts = [];
let head = 0;
while (head < queue.length) {
const node = queue[head++];
if (node === null) { parts.push('null'); continue; }
parts.push(String(node.val));
queue.push(node.left);
queue.push(node.right);
}
return parts.join(',');
}
deserialize(data) {
const tokens = data.split(',');
if (tokens[0] === 'null') return null;
const root = new TreeNode(parseInt(tokens[0]));
const queue = [root];
let i = 1, head = 0;
while (head < queue.length) {
const node = queue[head++];
if (tokens[i] !== 'null') {
node.left = new TreeNode(parseInt(tokens[i]));
queue.push(node.left);
}
i++;
if (tokens[i] !== 'null') {
node.right = new TreeNode(parseInt(tokens[i]));
queue.push(node.right);
}
i++;
}
return root;
}
}Tradeoff: Matches the LeetCode tree array format (level-order). Slightly more code but iterative — no recursion stack. Good to mention as an alternative if asked about iterative approaches.
HubSpot-specific tips
Start with the design contract: 'I'll use preorder traversal with explicit null markers — every tree has a unique preorder representation with nulls.' HubSpot interviewers value that framing. Explain why inorder alone is insufficient (ambiguous without a second traversal). The stateful index in deserialize is the trickiest part — use a closure variable or pass the index as a mutable object. Offer to implement BFS if they ask for an iterative version. This problem also tests OOP class design, which HubSpot specifically values.
Common mistakes
- Using inorder traversal without a complementary traversal — inorder alone doesn't uniquely identify a binary tree structure.
- Not handling null nodes explicitly in serialization — the structure is lost without null markers.
- Using a local index variable in deserialize without making it shared across recursive calls — each call gets a fresh index, breaking the token consumption.
- Forgetting to handle an empty tree (root = null) in serialize — return 'null' or an empty-node token consistently.
Follow-up questions
An interviewer at HubSpot may pivot to one of these next:
- Serialize and Deserialize BST (LC 449) — BSTs have an implicit null structure, so nulls can be omitted with tighter bounds.
- How would you compress the serialized format for a sparse tree?
- Design a format-agnostic codec (JSON, Protobuf, etc.) — what properties must any codec preserve?
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Why does preorder with null markers uniquely encode any binary tree?
Preorder visits root, left, right. With explicit null markers, the position of each null in the sequence precisely tells you where a left or right child is missing — no ambiguity remains.
Why not use inorder?
Inorder without nulls gives the sorted key sequence for a BST, but the structure is ambiguous — many trees can have the same inorder sequence. Inorder with nulls works but is less natural for reconstruction than preorder.
How does the shared idx variable work in JavaScript?
In the preorder solution, idx is declared in the outer scope (or as a property on this). Each recursive call to build() mutates idx as it consumes tokens, so successive calls pick up where the previous left off.
Practice these live with InterviewChamp.AI
Drill Serialize and Deserialize Binary Tree and other HubSpot interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.
Practice these live with InterviewChamp.AI →