Serialize and Deserialize BST
Advertisement
Problem
Design an algorithm to serialize and deserialize a BST. The encoded string should be as compact as possible.
Key insight (BST): Preorder traversal uniquely defines a BST. During deserialization, use min/max bounds to place each value correctly — no need to store null markers.
Solutions
// C++
string serialize(TreeNode* root) {
if (!root) return "";
string s = to_string(root->val) + " ";
s += serialize(root->left);
s += serialize(root->right);
return s;
}
TreeNode* deserialize(string data) {
istringstream iss(data);
queue<int> q;
int v;
while (iss >> v) q.push(v);
function<TreeNode*(int,int)> build = [&](int mn, int mx) -> TreeNode* {
if (q.empty() || q.front() < mn || q.front() > mx) return nullptr;
auto node = new TreeNode(q.front()); q.pop();
node->left = build(mn, node->val);
node->right = build(node->val, mx);
return node;
};
return build(INT_MIN, INT_MAX);
}
// Java
public String serialize(TreeNode root) {
if (root == null) return "";
return root.val + " " + serialize(root.left) + serialize(root.right);
}
public TreeNode deserialize(String data) {
if (data.isEmpty()) return null;
String[] parts = data.trim().split(" ");
Queue<Integer> q = new LinkedList<>();
for (String p : parts) q.add(Integer.parseInt(p));
return build(q, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
TreeNode build(Queue<Integer> q, int min, int max) {
if (q.isEmpty() || q.peek() < min || q.peek() > max) return null;
TreeNode node = new TreeNode(q.poll());
node.left = build(q, min, node.val);
node.right = build(q, node.val, max);
return node;
}
// JavaScript
function serialize(root) {
if (!root) return '';
return root.val + ' ' + serialize(root.left) + serialize(root.right);
}
function deserialize(data) {
if (!data) return null;
const vals = data.trim().split(' ').map(Number);
let i = 0;
function build(min, max) {
if (i >= vals.length || vals[i] < min || vals[i] > max) return null;
const node = new TreeNode(vals[i++]);
node.left = build(min, node.val);
node.right = build(node.val, max);
return node;
}
return build(-Infinity, Infinity);
}
# Python
def serialize(root):
def preorder(node):
if not node:
return []
return [node.val] + preorder(node.left) + preorder(node.right)
return ' '.join(map(str, preorder(root)))
def deserialize(data):
if not data:
return None
vals = iter(map(int, data.split()))
def build(mn, mx):
val = next(vals, None)
if val is None or val < mn or val > mx:
return None
# Problem: consumed the val; need to peek
# Use a list and index instead
return None
# Better iterative approach with index
vals = list(map(int, data.split()))
idx = [0]
def build2(mn, mx):
if idx[0] >= len(vals) or vals[idx[0]] < mn or vals[idx[0]] > mx:
return None
node = TreeNode(vals[idx[0]])
idx[0] += 1
node.left = build2(mn, node.val)
node.right = build2(node.val, mx)
return node
return build2(float('-inf'), float('inf'))
Complexity
- Time: O(n) serialize, O(n) deserialize
- Space: O(n)
Key Insight
Preorder + BST property is sufficient for unique reconstruction. No null markers needed, saving space.
Advertisement