Serialize and Deserialize Binary Tree
Design a codec for binary trees. serialize(root) turns a tree into a string, and deserialize(data) rebuilds the same tree from that string, with the same shape and the same value in every position. The format is yours to choose. Node values can be negative, and the tree can be empty.
Examples
root = [7,3,9,null,4] returns [7,3,9,null,4]
A level-order encoding with # for missing children writes this tree as "7,3,9,#,4,#,#,#,#". Decoding reads it back into the same shape.
root = [] returns []
An empty tree serializes to an empty string and comes back as null.
root = [-5,null,-5] returns [-5,null,-5]
Values repeat and are negative, and the only child is on the right. The null markers keep that child from moving to the left side.
Constraints
- 0 <= number of nodes <= 10^4
- -1000 <= Node.val <= 1000
Hints
A list of values alone loses information. What do you need to record so a left child and a right child can't be confused?
Write the tree in a traversal order, level order or preorder, and include a marker for every null child.
Serialize with a BFS that appends each value or # and enqueues both children of every real node. Deserialize with a second queue, assigning the next two tokens as the left and right children of each node you pop.
Drill This: Your Approach First
Approach
Walk the tree level by level with a queue and write every node's value, writing # for each missing child, separated by commas. To rebuild, read the first token as the root and push it onto a queue. For each node you pop, the next two tokens are its left and right children: create a node for each value and push it, or leave the child null for #. The null markers pin down the shape exactly, and the iterative walk avoids deep recursion on a skewed tree. O(n) time and space in both directions.
Time
O(n)
Space
O(n)
Pitfall
Solutions
public class Codec {
public String serialize(TreeNode root) {
if (root == null) return "";
StringBuilder sb = new StringBuilder();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
if (node == null) {
sb.append("#,");
continue;
}
sb.append(node.val).append(',');
queue.add(node.left);
queue.add(node.right);
}
return sb.toString();
}
public TreeNode deserialize(String data) {
if (data.isEmpty()) return null;
String[] tokens = data.split(",");
TreeNode root = new TreeNode(Integer.parseInt(tokens[0]));
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
int i = 1;
while (!queue.isEmpty()) {
TreeNode node = queue.poll();
if (!tokens[i].equals("#")) {
node.left = new TreeNode(Integer.parseInt(tokens[i]));
queue.add(node.left);
}
i++;
if (!tokens[i].equals("#")) {
node.right = new TreeNode(Integer.parseInt(tokens[i]));
queue.add(node.right);
}
i++;
}
return root;
}
}from collections import deque
from typing import Optional
class Codec:
def serialize(self, root: Optional[TreeNode]) -> str:
if not root:
return ""
out = []
queue = deque([root])
while queue:
node = queue.popleft()
if node is None:
out.append("#")
continue
out.append(str(node.val))
queue.append(node.left)
queue.append(node.right)
return ",".join(out)
def deserialize(self, data: str) -> Optional[TreeNode]:
if not data:
return None
tokens = data.split(",")
root = TreeNode(int(tokens[0]))
queue = deque([root])
i = 1
while queue:
node = queue.popleft()
if tokens[i] != "#":
node.left = TreeNode(int(tokens[i]))
queue.append(node.left)
i += 1
if tokens[i] != "#":
node.right = TreeNode(int(tokens[i]))
queue.append(node.right)
i += 1
return root