Recursive Range Validation
Intuition
A common mistake when validating a BST is to only check that each node's value is greater than its left child and less than its right child. This misses cases where a deeper node violates the BST property with respect to an ancestor. The correct approach is to pass down valid range bounds. Each node must fall within a range defined by its ancestors. The root can be any value, its left child must be less than the root, the left child's right child must be less than the root but greater than the left child, and so on. We track these bounds as we recurse.
Algorithm
- Define a helper function that takes a node and the valid range (min, max).
- If the node is null, return true (empty trees are valid BSTs).
- If the node's value is not strictly within (min, max), return false.
- Recursively validate the left subtree with the updated range (min, node.val).
- Recursively validate the right subtree with the updated range (node.val, max).
- Return true only if both subtrees are valid.
O(n)SpaceO(h) where h is the height of the treeCode (C++ · Java · Python · Go)
class Solution {
public:
bool isValidBST(TreeNode* root) {
return validate(root, LONG_MIN, LONG_MAX);
}
private:
bool validate(TreeNode* node, long minVal, long maxVal) {
if (node == nullptr) return true;
if (node->val <= minVal || node->val >= maxVal) return false;
return validate(node->left, minVal, node->val) &&
validate(node->right, node->val, maxVal);
}
};class Solution {
public boolean isValidBST(TreeNode root) {
return validate(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean validate(TreeNode node, long min, long max) {
if (node == null) return true;
if (node.val <= min || node.val >= max) return false;
return validate(node.left, min, node.val) &&
validate(node.right, node.val, max);
}
}def isValidBST(root: Optional[TreeNode]) -> bool:
def validate(node, min_val, max_val):
if not node:
return True
if node.val <= min_val or node.val >= max_val:
return False
return validate(node.left, min_val, node.val) and \
validate(node.right, node.val, max_val)
return validate(root, float('-inf'), float('inf'))import "math"
func isValidBST(root *TreeNode) bool {
return validate(root, math.MinInt64, math.MaxInt64)
}
func validate(node *TreeNode, minVal, maxVal int64) bool {
if node == nil {
return true
}
val := int64(node.Val)
if val <= minVal || val >= maxVal {
return false
}
return validate(node.Left, minVal, val) && validate(node.Right, val, maxVal)
}