Serialize and Deserialize Binary Tree in DSA Typescript - Time & Space Complexity
We want to understand how long it takes to convert a binary tree into a string and back.
How does the time grow as the tree gets bigger?
Analyze the time complexity of the following code snippet.
function serialize(root: TreeNode | null): string {
const parts = [];
function helper(node: TreeNode | null) {
if (!node) {
parts.push('#');
return;
}
parts.push(node.val.toString());
helper(node.left);
helper(node.right);
}
helper(root);
return parts.join(',');
}
function deserialize(data: string): TreeNode | null {
const nodes = data.split(',');
let i = 0;
function build(): TreeNode | null {
const val = nodes[i++];
if (val === '#') return null;
const node = new TreeNode(parseInt(val));
node.left = build();
node.right = build();
return node;
}
return build();
}
This code turns a binary tree into a string and then rebuilds the tree from that string.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Recursive traversal of each node in the tree.
- How many times: Each node is visited exactly once during serialization and once during deserialization.
As the number of nodes in the tree grows, the work grows proportionally.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 20 visits (10 nodes during serialize + 10 during deserialize) |
| 100 | About 200 visits |
| 1000 | About 2000 visits |
Pattern observation: The total work doubles but stays directly proportional to the number of nodes.
Time Complexity: O(n)
This means the time to serialize and deserialize grows linearly with the number of nodes in the tree.
[X] Wrong: "Serialization or deserialization takes more than linear time because of string operations or recursion overhead."
[OK] Correct: Each node is processed once, and string splitting or concatenation happens in a way that overall work stays proportional to the number of nodes.
Understanding this linear time complexity helps you explain how your solution scales and shows you can reason about recursive tree algorithms clearly.
"What if we used an iterative approach with a queue instead of recursion? How would the time complexity change?"
Practice
serialize and deserialize functions in the context of a binary tree?Solution
Step 1: Understand serialization
Serialization means converting a binary tree into a string format that can be stored or sent.Step 2: Understand deserialization
Deserialization means converting the string back into the original binary tree structure.Final Answer:
Convert a binary tree to a string and back to a binary tree -> Option CQuick Check:
Serialize + Deserialize = Convert tree to string and back [OK]
- Confusing serialization with sorting
- Thinking deserialization deletes nodes
- Mixing serialization with tree height calculation
Solution
Step 1: Identify input and output types
Deserialize takes a string (serialized data) and returns a TreeNode or null if empty.Step 2: Match correct signature
function deserialize(data: string): TreeNode | null matches input as string and output as TreeNode or null.Final Answer:
function deserialize(data: string): TreeNode | null -> Option AQuick Check:
Deserialize input string, output tree node [OK]
- Using number instead of string as input
- Returning string instead of tree node
- No input or void return type
"1,2,#,#,3,4,#,#,5,#,#", what is the inorder traversal of the deserialized tree?Solution
Step 1: Reconstruct tree from preorder string
Preorder: 1 (root), 2 (left), #,# (2's children null), 3 (right), 4 (3's left), #,# (4's children null), 5 (3's right), #,# (5's children null).Step 2: Perform inorder traversal (left, root, right)
Inorder: left subtree of 1 is 2, root 1, left subtree of 3 is 4, root 3, right subtree 5. So inorder is [2, 1, 4, 3, 5].Final Answer:
[2, 1, 4, 3, 5] -> Option BQuick Check:
Preorder string to tree, inorder traversal = [2,1,4,3,5] [OK]
- Confusing preorder with inorder
- Misplacing null markers
- Incorrect traversal order
function deserialize(data: string): TreeNode | null {
const values = data.split(",");
function build(): TreeNode | null {
if (!values.length) return null;
const val = values.shift();
if (val === "#") return null;
const node = new TreeNode(parseInt(val));
node.left = build();
node.right = build();
return node;
}
return build();
} What is the bug in this code if the input string is empty?Solution
Step 1: Check behavior on empty input
If data is empty string, values = [""], so values.length is 1, not zero.Step 2: Analyze values.shift() and val check
values.shift() returns "" (empty string), val === "#" is false, parseInt("") returns NaN, which may cause issues when creating TreeNode.Step 3: Identify actual bug
parseInt("") returns NaN, so TreeNode is created with NaN value, which is likely unintended.Final Answer:
parseInt('') returns NaN, creating invalid TreeNode -> Option DQuick Check:
Empty input leads to undefined or NaN node value [OK]
- Assuming empty string splits to empty array
- Ignoring parseInt('') returns NaN
- Thinking function never ends
Tree:
1
/ \ 2 3
/ \ 4 5
Options:
Solution
Step 1: Understand level-order traversal
Level order visits nodes level by level: root, then children left to right, including nulls for missing nodes.Step 2: Write level order for given tree
Level 1: 1
Level 2: 2, 3
Level 3: null, null (2's children), 4, 5 (3's children)
Level 4: nulls for 4 and 5's children
So serialized string is "1,2,3,null,null,4,5,null,null,null,null".Final Answer:
"1,2,3,null,null,4,5,null,null,null,null" -> Option AQuick Check:
Level order with nulls matches "1,2,3,null,null,4,5,null,null,null,null" [OK]
- Mixing preorder with level order
- Omitting null placeholders
- Swapping left and right children
Ready to prove it?
Pass the test and this pattern moves unknown
