Hard
Subtopics
binary-tree·breadth-first-search·depth-first-search·design·string·tree
Companies
amazon·apple·bloomberg·citadel·ebay·expedia·facebook·google·groupon·indeed·linkedin·microsoft·oracle·qualtrics·quora·salesforce·snapchat·tableau·uber·vmware·yahooLast updated: Oct 4, 2025
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.
Clarification: The input/output format is the same as how Leetcode serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.
publicclassCodec {
// Encodes a tree to a single string.public String serialize(TreeNode root) {
}
// Decodes your encoded data to tree.public TreeNode deserialize(String data) {
}
}
Now, we can serialize it to a string like these, treating nulls as ‘#’:
1
20,8,#,4,12,#,#,10,14,#,#,#,#
So, whenever a treenode is null, we have # and we stop tracking the children.
When deserialize the string, I assign left and right child for each not-null node, and add the not-null children to the queue, waiting to be handled later.
⏰ Time complexity: O(n) – each node is visited/processed a constant number of times during serialization and during deserialization, so work is linear in the number of nodes.
🧺 Space complexity: O(n) – the serialized string and the queue used during BFS can each hold O(n) elements in the worst case.
from collections import deque
classCodec:
defserialize(self, root: 'TreeNode') -> str:
ifnot root:
return"" res = []
q = deque([root])
while q:
node = q.popleft()
if node:
res.append(str(node.val))
q.append(node.left)
q.append(node.right)
else:
res.append("#")
return",".join(res)
defdeserialize(self, data: str) ->'TreeNode':
ifnot data:
returnNone arr = data.split(',')
root = TreeNode(int(arr[0]))
q = deque([root])
i =1while q and i < len(arr):
node = q.popleft()
if arr[i] !='#':
node.left = TreeNode(int(arr[i]))
q.append(node.left)
i +=1if i < len(arr) and arr[i] !='#':
node.right = TreeNode(int(arr[i]))
q.append(node.right)
i +=1return root
Method 2 - Preorder(or Postorder) and Inorder Traversal#
A simple solution is to store both Inorder and Preorder/Postorder traversals. This solution requires requires space twice the size of Binary Tree. Also, it will be harder to complete the solution in a single interview setting.
⏰ Time complexity: O(n) – building traversals and reconstructing the tree from inorder+preorder (or inorder+postorder) requires linear time when using index maps.
🧺 Space complexity: O(n) – storing two traversals and auxiliary maps/recursion uses linear space.
A single traversal like pre-order is not enough because it doesn’t capture the tree’s shape. For example, a pre-order sequence of [1, 2] could mean 2 is the left child of 1 OR the right child of 1. This ambiguity means crucial structural information is lost.
The key insight is that to preserve the tree’s structure, we must also preserve its emptiness. By augmenting the traversal to record null nodes (e.g., with a # marker), a single traversal becomes sufficient. The ambiguity is now resolved: a sequence of [1, 2, ...] definitively means 2 is the left child, while a sequence of [1, #, 2, ...] means 2 is the right child.
Split the serialized string into a queue of values.
Create a recursive build function that processes the queue.
Inside the build function, dequeue a value.
If the value is the null marker, return null.
Otherwise, create a new TreeNode with the value.
Crucially, make a recursive call to build to construct the node’s left child, and then another recursive call to construct its right child.
The pre-order sequence of the data ensures that the tree is reconstructed in the correct order. This approach is robust and works for all binary trees, including those with duplicate values.
⏰ Time complexity: O(n) – a single preorder traversal (with null markers) serializes the tree and deserialization consumes each token once to rebuild the tree recursively.
🧺 Space complexity: O(n) – the serialized representation and recursion stack (worst-case) use linear space.