297. Serialize and Deserialize Binary Tree
hardAsked at AtlassianSerialize and Deserialize Binary Tree is an Atlassian-favorite design problem. Implement two methods that convert a binary tree to a string and back, with no shared state between them. Atlassian asks it because it tests cleanly whether you can pick an unambiguous traversal and reverse it.
By Alex Chen, Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in Atlassian loops.
- Glassdoor (2026-Q1)— Atlassian SWE-III / Senior onsite reports cite Serialize-Deserialize Binary Tree as a recurring tree-design problem.
- Blind (2025-09)— Atlassian interview threads list it as 'the design-a-format' question — interviewer cares as much about the format choice as the code.
Problem
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment. 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.
Constraints
The number of nodes in the tree is in the range [0, 10^4].-1000 <= Node.val <= 1000
Examples
Example 1
root = [1,2,3,null,null,4,5][1,2,3,null,null,4,5]Example 2
root = [][]Approaches
1. Preorder DFS with null sentinel
Serialize via preorder DFS, emitting '#' for null. Deserialize by popping tokens in the same order — null token returns null, otherwise build node + recurse left + recurse right.
- Time
- O(n) both ways
- Space
- O(n)
function serialize(root) {
const parts = [];
const dfs = (node) => {
if (!node) {
parts.push('#');
return;
}
parts.push(String(node.val));
dfs(node.left);
dfs(node.right);
};
dfs(root);
return parts.join(',');
}
function deserialize(data) {
if (!data) return null;
const tokens = data.split(',');
let i = 0;
const build = () => {
if (i >= tokens.length) return null;
const t = tokens[i++];
if (t === '#') return null;
const node = { val: Number(t), left: null, right: null };
node.left = build();
node.right = build();
return node;
};
return build();
}Tradeoff: Cleanest code. The null sentinel is what makes preorder reversible — without it preorder alone can't distinguish [1,2,null,null,3] from [1,null,2,null,3]. Atlassian-canonical answer.
2. Level-order BFS (mirrors LeetCode's own format)
Serialize via BFS using a queue, emitting node values and 'null' for missing children. Deserialize by reading the tokens and using a queue to attach children level-by-level.
- Time
- O(n) both ways
- Space
- O(n)
function serializeBFS(root) {
if (!root) return '';
const out = [];
const queue = [root];
while (queue.length) {
const node = queue.shift();
if (node === null) {
out.push('null');
continue;
}
out.push(String(node.val));
queue.push(node.left);
queue.push(node.right);
}
return out.join(',');
}
function deserializeBFS(data) {
if (!data) return null;
const tokens = data.split(',');
const root = { val: Number(tokens[0]), left: null, right: null };
const queue = [root];
let i = 1;
while (queue.length && i < tokens.length) {
const node = queue.shift();
if (tokens[i] !== 'null') {
node.left = { val: Number(tokens[i]), left: null, right: null };
queue.push(node.left);
}
i++;
if (i < tokens.length && tokens[i] !== 'null') {
node.right = { val: Number(tokens[i]), left: null, right: null };
queue.push(node.right);
}
i++;
}
return root;
}Tradeoff: Matches LeetCode's own [1,2,3,null,null,4,5] format which is great for debugging. Slightly more code. Use this if the interviewer pushes you to 'make the output human-readable'.
Atlassian-specific tips
Atlassian interviewers grade format choice as much as correctness. Open with: 'I'll use preorder with a null sentinel because preorder alone is reversible with the null marker but not without.' Then code. After you finish they often ask 'why not just emit the values in preorder?' — your answer should be the [1,2,null,null,3] vs [1,null,2,null,3] ambiguity. Memorize this argument; it's the load-bearing rubric point.
Common mistakes
- Emitting only non-null values in preorder — the result is ambiguous (multiple trees produce the same string).
- Using a global token-index variable without re-initializing — the second deserialize call starts from where the first left off.
- Building each node with `new TreeNode(val)` style without first defining TreeNode — LeetCode's harness provides it but your local sketch may not.
Follow-up questions
An interviewer at Atlassian may pivot to one of these next:
- Serialize and Deserialize BST (LeetCode 449) — exploit BST property to skip the null sentinel.
- Serialize and Deserialize N-ary Tree (LeetCode 428) — children are a variable-length list; encode count or use a delimiter.
- How would you serialize a tree that has a parent pointer too? Store node ID, parent ID — flat list.
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Preorder or level-order at Atlassian?
Either is accepted on correctness. Preorder is the canonical answer because the recursion is cleaner and the null-sentinel argument scores rubric points. Level-order shines on the 'human-readable format' follow-up.
Why doesn't preorder alone work?
Because preorder of [1,2,3] (left chain) and preorder of [1,null,2,3] (right chain from 1, left chain from 2) are both 1,2,3. The null marker disambiguates: '1,2,3' becomes '1,2,#,#,3,#,#' for one tree and '1,#,2,3,#,#,#' for the other. Once you see this you never forget it.
Free learning resources
Curated free links for this problem.
Practice these live with InterviewChamp.AI
Drill Serialize and Deserialize Binary Tree and other Atlassian interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.
Practice these live with InterviewChamp.AI →