Verify Preorder Sequence in Binary Search Tree

Updated on 30 June, 2025
Verify Preorder Sequence in Binary Search Tree header image

Problem Statement

In this task, we are given an array of unique integers, preorder, representing the preorder traversal sequence of nodes' values from a binary search tree (BST). The challenge requires us to determine if the sequence can represent a correct preorder traversal of a BST. Specifically, in a valid BST, for any node:

  • The left subtree has nodes with values less than the node's value.
  • The right subtree has nodes with values greater than the node's value.
  • Both the left and right subtrees must also be binary search trees.

Given such constraints, our task is to assess if the input preorder array meets the criteria of a legitimate preorder traversal sequence of a BST.

Examples

Example 1

Input:

preorder = [5,2,1,3,6]

Output:

true

Example 2

Input:

preorder = [5,2,6,1,3]

Output:

false

Constraints

  • 1 <= preorder.length <= 104
  • 1 <= preorder[i] <= 104
  • All the elements of preorder are unique.

Approach and Intuition

Given the constraints that all elements in the preorder array are unique, and the nature of binary search trees, we can derive the following approach based on the nature of preorder traversal (node, left, right):

  1. Use a stack to simulate the insertion of elements in a BST constructed using the preorder sequence.
    • Starting from the first element which represents the root, push it onto the stack.
  2. Initialize a variable, say lower_bound, to track the lower permissible bound of the next node value (this helps in verifying the properties of BST during the simulation).
  3. Traverse the array from the second element onward.
    • For each element:
      • If it is less than the lower_bound, return false as this violates the BST property.
      • Keep popping from the stack as long as the current element is greater than the stack’s top (indicating the end of a left subtree and the start of a right subtree), and update the lower_bound to the popped value.
      • Push the current element onto the stack.
  4. If the entire preorder sequence can be processed without contradiction, return true.

By this, we effectively simulate the construction of the BST and check in real-time if any element violates the conditions which would make it not represent a valid binary search tree's preorder traversal sequence. This method leverages BST properties efficiently and ensures that the sequence's integrity as a preorder traversal is maintained.

Solutions

  • C++
  • Java
  • Python
cpp
class Solution {
public:
    bool isValidPreorder(vector<int>& preorder) {
        int index = 0;
        return validate(preorder, index, INT_MIN, INT_MAX);
    }
        
    bool validate(vector<int>& nodes, int& idx, int lower, int upper) {
        if (idx == nodes.size()) {
            return true;
        }
            
        int nodeVal = nodes[idx];
        if (nodeVal <= lower || nodeVal >= upper) {
            return false;
        }
            
        idx++;
        bool validLeftSubtree = validate(nodes, idx, lower, nodeVal);
        bool validRightSubtree = validate(nodes, idx, nodeVal, upper);
        return validLeftSubtree || validRightSubtree;
    }
};

The provided solution in C++ addresses the problem of verifying whether a given sequence represents a valid preorder traversal of a binary search tree (BST). The implementation uses a recursive helper function to validate each node in the sequence by checking it against a dynamically updated range (lower and upper bounds).

  • Here's an overview of the solution:

    • A class Solution contains a public method isValidPreorder which initializes the process.
    • The isValidPreorder function relies on a private helper method validate, which recurses through the sequence.
    • The validate method checks if the current value falls within the valid range for a BST node given the constraints set by previously processed nodes.
    • The function advances the sequence using an index reference and recursively validates both the left and right subtrees, updating the ranges accordingly.
    • If a node fails to meet the constraints for either subtree, the function returns false, otherwise, it continues until the sequence is entirely validated.
  • Specific conditions and updates within the recursive function ensure both the correct structure of the BST and adherence to preorder traversal rules:

    • The base case checks whether the end of the sequence is reached, returning true in such a case.
    • An immediate return of false occurs if a node value does not lie within the expected range.
    • Recursions account for both left and right children, with the index progressing linearly through the preorder list, and range limits adjusting to narrow down permissible values for subsequent nodes.
  • The use of a reference to the index variable allows the function to keep track of the current position in the sequence across recursive calls without duplicating the list or slicing it, enhancing both space and time efficiency.

Overall, the C++ solution effectively validates a sequence against the properties of a BST in a preorder manner, utilizing recursive techniques with range validation. This ensures each node is placed correctly according to BST rules and the order of nodes strictly follows a preorder traversal.

java
class Solution {
    public boolean isValidPreorder(int[] preorderSequence) {
        int[] index = {0};
        return traverse(preorderSequence, index, Integer.MIN_VALUE, Integer.MAX_VALUE);
    }
        
    public boolean traverse(int[] preorderSequence, int[] index, int lower, int upper) {
        if (index[0] == preorderSequence.length) {
            return true;
        }
            
        int currentValue = preorderSequence[index[0]];
        if (currentValue <= lower || currentValue >= upper) {
            return false;
        }
            
        index[0]++;
        boolean leftTreeValid = traverse(preorderSequence, index, lower, currentValue);
        boolean rightTreeValid = traverse(preorderSequence, index, currentValue, upper);
        return leftTreeValid || rightTreeValid;
    }
}

The provided Java solution checks if a given array represents a valid preorder traversal sequence of a binary search tree (BST). The cornerstone of the implementation is the isValidPreorder method, which leverages a helper method traverse to navigate recursively through the array based on predetermined BST properties.

Here's how the solution operates:

  • Start by initializing an array index (used to track the current position in the preorderSequence) with its initial value set to 0.
  • Use the traverse method recursively to verify each segment of the preorderSequence. The traversal checks:
    • The current value must lie strictly between the lower and upper bounds to adhere to BST properties.
    • The method first checks the left subtree, ensuring all values adhere to the bounds set by the current node's value. It recursively checks this condition with the updated bounds for each node in the BST's left subtree.
    • Having validated the left subtree, the method proceeds to execute similar checks on the right subtree, this time using the current node's value as the new lower bound.
  • If at any point, a value in the sequence does not comply with the conditions of the BST, the function immediately returns false.
  • The isValidPreorder function finally returns true if all nodes in the sequence meet BST conditions, and false otherwise.

This approach ensures that all constraints typical of a binary search tree are systematically validated across the whole sequence, leveraging recursion for depth-first validation of each subtree. Hence, you can rapidly determine the validity of the preorder sequence with respect to BST properties.

python
class Solution:
    def isValidPreorder(self, preorder: List[int]) -> bool:
        def check_subtree(index, lower, upper):
            if index[0] == len(preorder):
                return True
                
            value = preorder[index[0]]
            if not lower < value < upper:
                return False
    
            index[0] += 1
            left_valid = check_subtree(index, lower, value)
            right_valid = check_subtree(index, value, upper)
            return left_valid or right_valid
                
        return check_subtree([0], float('-inf'), float('inf'))

The given solution focuses on verifying if a given list of integers represents a valid preorder traversal of a binary search tree (BST). The code is implemented in Python and utilizes recursion to achieve this. Here's how the provided solution addresses the problem:

  • Define a nested utility function check_subtree, which recursively checks the validity of the subtree. It uses parameters index, lower, and upper to maintain the current index of the list and the bounds within which the current node value must lie.
  • If the end of the list is reached, it indicates that all elements have been processed and conformed to the BST properties, thus returning True.
  • The value of the current node is compared against the bounds. If the value does not respect the BST property (lower < value < upper), the function returns False.
  • Recursively call check_subtree for the left subtree, setting the upper bound to the current node's value and for the right subtree, setting the lower bound to the node’s value.
  • The result of the subtree checks is combined using logical OR to determine the validity of the entire tree.

Overall, the algorithm effectively utilizes recursive checks within specified bounds to verify the authenticity of a preorder sequence as that of a BST. This solution is concise and efficiently handles the validation by leveraging the properties of BST and preorder traversal rules.

Comments

No comments yet.