Talentd
FleetCode
Make and follow sheets.Sign in

Serialize and Deserialize BST solution and explanation

MediumBinary Search TreeBinary TreeBreadth-First SearchDepth-First Search6 min read60.1% acceptanceUpdated 9 Apr 2026
花花酱 LeetCode 449. Serialize and Deserialize BST - 刷题找工作 EP91Hua Hua · 14:27 · 8K viewsWatch on YouTube
9 more videos on this problem
  1. 花花酱 LeetCode 449. Serialize and Deserialize BST - 刷题找工作 EP91Hua Hua · 14:27 · 8K views
  2. Serialize and Deserialize BST | Leetcode 449 | Recursive DFS | Facebook Amazon MicrosoftNaresh Gupta · 10:04 · 5K views
  3. Leetcode - Serialize and Deserialize BST (Python)Timothy H Chang · 12:26 · 2K views
  4. Serialize and Deserialize BST | Serialize and Deserialize Binary Search Tree | LeetCode 449Programming Tutorials · 15:01 · 2K views
  5. Serialize and Deserialization Binary Tree, BST deserialization Explained. Leetcode 297, 449InterviewDose · 11:02 · 2K views
  6. Serialize and Deserialize BST | Leet code 449 | Theory explained + Python codeSai Anish Malla · 19:07 · 1K views
  7. Serialize and Deserialize BST Leetcode | Leetcode 449 | Leetcode October ChallengeCode Bashers · 17:55 · 880 views
  8. Daily Leetcode #192: Oct 09, 2020 - 449. Serialize and Deserialize BSTProgramming Live with Larry · 10:33 · 374 views
  9. Serialize and Deserialize BST/Binary Tree: Leetcode 449/297Tony Teaches · 22:10 · 263 views
  10. Leetcode 449: Serialize and Deserialize BST | Master Trees | Intuition and ApproachCode Concepts with Animesh · 26:52 · 214 views

The problem

Serialization is 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 search tree. There is no restriction on how your serialization/deserialization algorithm should work. You need to ensure that a binary search tree can be serialized to a string, and this string can be deserialized to the original tree structure.

The encoded string should be as compact as possible.

Example 1:

Input: root = [2,1,3]
Output: [2,1,3]

Example 2:

Input: root = []
Output: []

Constraints:

  • The number of nodes in the tree is in the range [0, 104].
  • 0 <= Node.val <= 104
  • The input tree is guaranteed to be a binary search tree.

Approach overview

Problem Overview: Design two functions: serialize converts a Binary Search Tree (BST) into a string, and deserialize reconstructs the same tree from that string. The key constraint is preserving the BST structure so that the reconstructed tree matches the original.

Approach 1: Pre-order Traversal (O(n) time, O(n) space)

This method leverages the properties of a binary search tree. Perform a pre-order traversal (root → left → right) and store node values in sequence. Because BST nodes follow ordering rules, you can rebuild the tree without explicitly storing null markers. During deserialization, read values in order and reconstruct the tree using value bounds. Each recursive call consumes the next valid value that falls within the allowed range. This approach performs a single pass over the nodes, giving O(n) time complexity and O(n) space for the serialized string and recursion stack.

Approach 2: Level-order Traversal (O(n) time, O(n) space)

This approach treats the BST like a general binary tree and uses breadth-first traversal. During serialization, perform a level-order traversal with a queue and append node values to the output string. Include placeholders for missing children so the exact structure can be reconstructed later. During deserialization, read values sequentially and rebuild the tree by assigning left and right children while iterating through the queue. This technique uses a queue and is based on breadth-first search, making it straightforward to implement even if BST ordering properties are ignored. Time complexity remains O(n), and the queue plus serialized data require O(n) space.

Recommended for interviews: The pre-order traversal approach is usually preferred. It takes advantage of BST ordering to avoid storing null markers, producing a more compact serialization. Interviewers often expect candidates to recognize that the BST property allows reconstruction using value ranges with a depth-first search strategy. The level-order method still works and demonstrates solid understanding of tree serialization, but it does not fully utilize the BST constraint.

Approach 1: Approach 1: Pre-order Traversal

In this approach, we utilize pre-order traversal (Root-Left-Right) to serialize the BST. The serialized string will be a space-separated string that represents the order of visiting nodes during pre-order traversal.

During deserialization, you use the properties of the pre-order traversal and BST to reconstruct the tree. The key is to maintain the order of insertions such that it respects BST properties.

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

class Codec:

    def serialize(self, root):
        def preorder(node):
            return [str(node.val)] + preorder(node.left) + preorder(node.right) if node else []

        return ' '.join(preorder(root))

    def deserialize(self, data):
        if not data:
            return None

        def buildTree(bounds):
            if not data or not(bounds[0] < int(data[-1]) < bounds[1]):
                return None

            val = int(data.pop())
            node = TreeNode(val)
            node.right = buildTree((val, bounds[1]))
            node.left = buildTree((bounds[0], val))
            return node

        data = data.split()[::-1]
        return buildTree((-float('inf'), float('inf')))
#include <string>
#include <sstream>
#include <vector>
#include <climits>
#include <algorithm>

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

class Codec {
public:

    // Encodes a tree to a single string.
    std::string serialize(TreeNode* root) {
        std::string data;
        preorder(root, data);
        return data;
    }

    // Decodes your encoded data to tree.
    TreeNode* deserialize(std::string data) {
        std::istringstream iss(data);
        std::vector<int> nodes;
        std::string token;
        while (iss >> token) {
            nodes.push_back(std::stoi(token));
        }
        std::reverse(nodes.begin(), nodes.end());
        return buildTree(nodes, INT_MIN, INT_MAX);
    }

private:

    void preorder(TreeNode* node, std::string& data) {
        if (node) {
            data += std::to_string(node->val) + " ";
            preorder(node->left, data);
            preorder(node->right, data);
        }
    }

    TreeNode* buildTree(std::vector<int>& nodes, int lower, int upper) {
        if (nodes.empty() || nodes.back() < lower || nodes.back() > upper) {
            return nullptr;
        }

        int val = nodes.back();
        nodes.pop_back();
        TreeNode* node = new TreeNode(val);
        node->right = buildTree(nodes, val, upper);
        node->left = buildTree(nodes, lower, val);
        return node;
    }
};

The serialize function performs a pre-order traversal to create a space-separated string of node values. The deserialize function reads from this string (reversed) and reconstructs the tree by checking the constraints for valid BST nodes, creating a tree using bounds for node values as it progresses.

Complexity

Time Complexity: O(n) for both serialization and deserialization, where n is the number of nodes.
Space Complexity: O(n) for storing the serialized data.

Try this approach in the editor

Approach 2: Approach 2: Level-order Traversal

Level-order traversal (BFS) involves visiting each level of the tree one at a time, which can be used to serialize the tree into a compact form. For empty positions, we can indicate using a special character (e.g., '#'). This method guarantees that we record the full structure of the tree including missing nodes.

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

import java.util.*;

public class Codec {

    // Encodes a tree to a single string.
    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(node.val).append(",");
                queue.add(node.left);
                queue.add(node.right);
            } else {
                sb.append("null,");
            }
        }
        sb.setLength(sb.length() - 1);
        return sb.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if (data.equals("[]")) return null;

        String[] nodes = data.split(",");
        TreeNode root = new TreeNode(Integer.parseInt(nodes[0]));
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        int i = 1;
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (!nodes[i].equals("null")) {
                node.left = new TreeNode(Integer.parseInt(nodes[i]));
                queue.add(node.left);
            }
            i++;
            if (!nodes[i].equals("null")) {
                node.right = new TreeNode(Integer.parseInt(nodes[i]));
                queue.add(node.right);
            }
            i++;
        }
        return root;
    }
}
function TreeNode(val) {
  this.val = val;
  this.left = this.right = null;
}

var Codec = function() {};

Codec.prototype.serialize = function(root) {
  if (!root) return '[]';
  const queue = [root];
  let result = '';
  while (queue.length) {
    const node = queue.shift();
    if (node) {
      result += node.val + ',';
      queue.push(node.left);
      queue.push(node.right);
    } else {
      result += 'null,';
    }
  }
  return result.slice(0, -1);
};

Codec.prototype.deserialize = function(data) {
  if (data === '[]') return null;
  const nodes = data.split(',');
  const root = new TreeNode(parseInt(nodes[0]));
  const queue = [root];
  let i = 1;
  while (queue.length) {
    const node = queue.shift();
    if (nodes[i] !== 'null') {
      node.left = new TreeNode(parseInt(nodes[i]));
      queue.push(node.left);
    }
    i++;
    if (nodes[i] !== 'null') {
      node.right = new TreeNode(parseInt(nodes[i]));
      queue.push(node.right);
    }
    i++;
  }
  return root;
};

This Java solution serialized the BST using a level-order traversal, noting nulls for missing children. During deserialization, nodes are reconstructed level by level, keeping track of parents and appending appropriate left and right children.

Complexity

Time Complexity: O(n) for both serialization and deserialization.
Space Complexity: O(n) due to the queue usage in both processes.

Try this approach in the editor

Approach 3: Default Approach

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */

type Codec struct {
}

func Constructor() Codec {
	return Codec{}
}

// Serializes a tree to a single string.
func (this *Codec) serialize(root *TreeNode) string {
	if root == nil {
		return ""
	}
	data := &strings.Builder{}
	var dfs func(*TreeNode)
	dfs = func(root *TreeNode) {
		if root == nil {
			return
		}
		data.WriteString(strconv.Itoa(root.Val))
		data.WriteByte(' ')
		dfs(root.Left)
		dfs(root.Right)
	}
	dfs(root)
	return data.String()[0 : data.Len()-1]
}

// Deserializes your encoded data to tree.
func (this *Codec) deserialize(data string) *TreeNode {
	if data == "" {
		return nil
	}
	vals := strings.Split(data, " ")
	i := 0
	var dfs func(int, int) *TreeNode
	dfs = func(mi, mx int) *TreeNode {
		if i == len(vals) {
			return nil
		}
		x, _ := strconv.Atoi(vals[i])
		if x < mi || x > mx {
			return nil
		}
		i++
		root := &TreeNode{Val: x}
		root.Left = dfs(mi, x)
		root.Right = dfs(x, mx)
		return root
	}
	return dfs(math.MinInt64, math.MaxInt64)
}

/**
 * Your Codec object will be instantiated and called as such:
 * ser := Constructor()
 * deser := Constructor()
 * tree := ser.serialize(root)
 * ans := deser.deserialize(tree)
 * return ans
 */
Try this approach in the editor

Complexity comparison

ApproachComplexity
Approach 1: Pre-order Traversal

Time Complexity: O(n) for both serialization and deserialization, where n is the number of nodes.
Space Complexity: O(n) for storing the serialized data.

Approach 2: Level-order Traversal

Time Complexity: O(n) for both serialization and deserialization.
Space Complexity: O(n) due to the queue usage in both processes.

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Pre-order Traversal with BST BoundsO(n)O(n)Best when leveraging BST properties for compact serialization
Level-order Traversal (BFS)O(n)O(n)Useful when treating the tree as a generic binary tree or implementing with queues

Frequently asked questions

Is Serialize and Deserialize BST easy or hard?

Serialize and Deserialize BST is considered a medium-level problem. The serialization step is straightforward, but the challenge lies in reconstructing the BST efficiently using traversal order and value constraints.

Serialize and Deserialize BST Python/Java solution

Python and C++ solutions commonly use preorder traversal with recursion and value bounds. Java and JavaScript implementations often demonstrate level-order traversal using a queue. Both approaches achieve O(n) time complexity while reconstructing the exact tree structure.

How to solve Serialize and Deserialize BST in O(n)?

Traverse the BST using preorder and store values in sequence. During deserialization, rebuild the tree by reading values and enforcing lower and upper bounds for each subtree. Because each value is processed once and inserted in the correct position immediately, the entire process runs in linear time.

What is the best approach for Serialize and Deserialize BST?

The most efficient approach uses preorder traversal with BST value bounds. Serialize the tree by recording nodes in preorder, then reconstruct it by inserting values within valid min/max ranges. This leverages BST ordering and avoids storing null markers, keeping both time and space complexity at O(n).

Is Serialize and Deserialize BST asked at Google/Amazon/Meta?

Tree serialization problems frequently appear in interviews at companies like Google, Amazon, and Meta. Variations such as Serialize and Deserialize Binary Tree or BST test understanding of traversal, recursion, and data structure design.

What data structure is used in Serialize and Deserialize BST?

The solution typically uses recursion with preorder traversal for DFS-based reconstruction or a queue for BFS level-order traversal. The BST property is critical for the optimized preorder approach because it allows reconstruction using value ranges.

What is the time complexity of Serialize and Deserialize BST?

Both serialization and deserialization run in O(n) time where n is the number of nodes. Each node is processed exactly once during traversal and reconstruction. Space complexity is O(n) due to the output string and recursion or queue storage.

Comments

Now write it yourselfClose this page and solve Serialize and Deserialize BST in the editor, without looking.
Practise Serialize and Deserialize BST