Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

331. Verify Preorder Serialization of a Binary Tree - Leetcode Solution

Problem Description

The problem asks you to verify whether a given preorder serialization of a binary tree is valid. The serialization is provided as a string, with each node's value separated by commas. Null nodes are represented by the character #.

For example, the string "9,3,4,#,#,1,#,#,2,#,6,#,#" represents the preorder traversal of a binary tree, where each node or # is visited in preorder (root, left, right).

  • You must determine if this serialization could represent a valid binary tree.
  • Each non-null node (number) must have exactly two children (which can be # for null).
  • The input string contains only integers and # separated by commas.
  • Assume only one valid binary tree structure is possible for a valid serialization.

Code Implementation

class Solution:
    def isValidSerialization(self, preorder: str) -> bool:
        slots = 1
        for node in preorder.split(','):
            slots -= 1
            if slots < 0:
                return False
            if node != '#':
                slots += 2
        return slots == 0
      
class Solution {
public:
    bool isValidSerialization(string preorder) {
        int slots = 1;
        int n = preorder.size();
        for (int i = 0; i < n;) {
            if (slots == 0) return false;
            if (preorder[i] == '#') {
                slots--;
                i++;
            } else {
                // Parse number
                while (i < n && preorder[i] != ',') i++;
                slots++; // slots = slots - 1 + 2
            }
            // Skip comma
            while (i < n && preorder[i] == ',') i++;
        }
        return slots == 0;
    }
};
      
class Solution {
    public boolean isValidSerialization(String preorder) {
        int slots = 1;
        String[] nodes = preorder.split(",");
        for (String node : nodes) {
            slots--;
            if (slots < 0) return false;
            if (!node.equals("#")) slots += 2;
        }
        return slots == 0;
    }
}
      
var isValidSerialization = function(preorder) {
    let slots = 1;
    const nodes = preorder.split(',');
    for (let node of nodes) {
        slots--;
        if (slots < 0) return false;
        if (node !== '#') slots += 2;
    }
    return slots === 0;
};
      

Thought Process

When first encountering this problem, you might try to reconstruct the binary tree explicitly while parsing the string. This approach would involve building tree nodes and checking if the structure is valid, but this is unnecessary and inefficient.

Instead, we can focus on the properties of preorder traversal and serialization. Each non-null node provides two "slots" for its children, while each node (including nulls) consumes one slot. If, at any point, we run out of slots before finishing the traversal, or if there are leftover slots at the end, the serialization is invalid.

The key insight is recognizing that we can validate the structure by counting available slots as we process each node, rather than reconstructing the tree itself.

Solution Approach

  • Start with 1 slot (for the root node).
  • Iterate through each value in the preorder serialization (splitting by commas).
  • For each node:
    • Consume 1 slot (since every node, null or not, occupies a position in the tree).
    • If the current node is a non-null value (not #), add 2 slots (since it can have two children).
  • If at any point the slot count goes negative, return false (more nodes than possible slots).
  • At the end, check that the slot count is exactly zero (all slots are filled perfectly).

This approach is efficient because it requires only a single pass through the input and no extra data structures.

Example Walkthrough

Let's walk through the input "9,3,4,#,#,1,#,#,2,#,6,#,#" step by step:

  1. Start with 1 slot.
  2. Read "9": slots = 0 (consume 1) + 2 (add 2) = 2.
  3. Read "3": slots = 1 + 2 = 3.
  4. Read "4": slots = 2 + 2 = 4.
  5. Read "#": slots = 3.
  6. Read "#": slots = 2.
  7. Read "1": slots = 1 + 2 = 3.
  8. Read "#": slots = 2.
  9. Read "#": slots = 1.
  10. Read "2": slots = 0 + 2 = 2.
  11. Read "#": slots = 1.
  12. Read "6": slots = 0 + 2 = 2.
  13. Read "#": slots = 1.
  14. Read "#": slots = 0.

At the end, slots = 0, so the serialization is valid.

Time and Space Complexity

  • Brute-force Approach: Reconstructing the tree explicitly would take O(N) time and O(N) space, where N is the number of nodes/values, due to creating node objects and possibly storing them in a stack or tree structure.
  • Optimized Approach (Slot Counting): This method takes O(N) time (one pass through the input) and O(1) space (just an integer counter and the split array).
  • The space for splitting the string into an array is O(N), but no additional data structures are needed for validation.

Summary

The key to solving this problem efficiently is understanding the relationship between nodes and available child "slots" in a binary tree. By counting slots as we process each node, we can validate the serialization in a single pass without reconstructing the tree. This elegant approach is both time and space efficient, and highlights how careful reasoning about binary tree properties can simplify complex problems.