🧠
Better (Top-Down Min/Max Range Validation)
💡 This approach uses the BST property as a range constraint passed down the tree, avoiding repeated subtree traversals and improving efficiency.
Intuition
Each node must lie within a valid range defined by its ancestors. We recursively check if node values respect these min and max bounds.
Algorithm
- Start with the root node and an initial range (-infinity, +infinity).
- Check if the current node's value lies within the allowed range.
- Recursively validate the left subtree with updated max bound as current node's value.
- Recursively validate the right subtree with updated min bound as current node's value.
💡 Passing down constraints is a key insight that avoids redundant subtree scans and ensures global BST validity.
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def is_valid_bst(root):
def helper(node, low, high):
if not node:
return True
if node.val <= low or node.val >= high:
return False
return helper(node.left, low, node.val) and helper(node.right, node.val, high)
return helper(root, float('-inf'), float('inf'))
# Driver code
if __name__ == '__main__':
root = TreeNode(2, TreeNode(1), TreeNode(3))
print(is_valid_bst(root)) # True
root2 = TreeNode(5, TreeNode(1), TreeNode(4, TreeNode(3), TreeNode(6)))
print(is_valid_bst(root2)) # False
Line Notes
class TreeNode:Define TreeNode class to represent nodes in the binary tree
def is_valid_bst(root):Main function to validate BST using helper
def helper(node, low, high):Helper function carries current valid range for node values
if not node:Base case: empty subtree is valid
if node.val <= low or node.val >= high:Check if current node violates BST range constraints
return helper(node.left, low, node.val) and helper(node.right, node.val, high)Recursively validate left and right subtrees with updated ranges
return helper(root, float('-inf'), float('inf'))Start recursion with full range
class TreeNode {
int val;
TreeNode left, right;
TreeNode(int val) { this.val = val; }
}
public class Solution {
public boolean isValidBST(TreeNode root) {
return helper(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean helper(TreeNode node, long low, long high) {
if (node == null) return true;
if (node.val <= low || node.val >= high) return false;
return helper(node.left, low, node.val) && helper(node.right, node.val, high);
}
public static void main(String[] args) {
Solution sol = new Solution();
TreeNode root = new TreeNode(2);
root.left = new TreeNode(1);
root.right = new TreeNode(3);
System.out.println(sol.isValidBST(root)); // true
TreeNode root2 = new TreeNode(5);
root2.left = new TreeNode(1);
root2.right = new TreeNode(4);
root2.right.left = new TreeNode(3);
root2.right.right = new TreeNode(6);
System.out.println(sol.isValidBST(root2)); // false
}
}
Line Notes
class TreeNode {Define TreeNode class to represent nodes in the binary tree
public boolean isValidBST(TreeNode root) {Entry point calls helper with full integer range
private boolean helper(TreeNode node, long low, long high) {Helper function with range constraints passed as long to avoid overflow
if (node == null) return true;Empty subtree is valid BST
if (node.val <= low || node.val >= high) return false;Check if node violates allowed range
return helper(node.left, low, node.val) && helper(node.right, node.val, high);Recurse with updated bounds for left and right subtrees
#include <iostream>
#include <climits>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
bool helper(TreeNode* node, long low, long high) {
if (!node) return true;
if (node->val <= low || node->val >= high) return false;
return helper(node->left, low, node->val) && helper(node->right, node->val, high);
}
bool isValidBST(TreeNode* root) {
return helper(root, LONG_MIN, LONG_MAX);
}
int main() {
TreeNode* root = new TreeNode(2);
root->left = new TreeNode(1);
root->right = new TreeNode(3);
cout << boolalpha << isValidBST(root) << endl; // true
TreeNode* root2 = new TreeNode(5);
root2->left = new TreeNode(1);
root2->right = new TreeNode(4);
root2->right->left = new TreeNode(3);
root2->right->right = new TreeNode(6);
cout << boolalpha << isValidBST(root2) << endl; // false
return 0;
}
Line Notes
struct TreeNode {Define TreeNode struct to represent nodes in the binary tree
bool helper(TreeNode* node, long low, long high) {Helper function with range constraints passed as long to avoid overflow
if (!node) return true;Empty subtree is valid BST
if (node->val <= low || node->val >= high) return false;Check if node violates BST property with current bounds
return helper(node->left, low, node->val) && helper(node->right, node->val, high);Recurse with updated bounds for left and right subtrees
class TreeNode {
constructor(val=0, left=null, right=null) {
this.val = val;
this.left = left;
this.right = right;
}
}
function isValidBST(root) {
function helper(node, low, high) {
if (!node) return true;
if (node.val <= low || node.val >= high) return false;
return helper(node.left, low, node.val) && helper(node.right, node.val, high);
}
return helper(root, -Infinity, Infinity);
}
// Test cases
const root = new TreeNode(2, new TreeNode(1), new TreeNode(3));
console.log(isValidBST(root)); // true
const root2 = new TreeNode(5, new TreeNode(1), new TreeNode(4, new TreeNode(3), new TreeNode(6)));
console.log(isValidBST(root2)); // false
Line Notes
class TreeNode {Define TreeNode class to represent nodes in the binary tree
function isValidBST(root) {Main function to validate BST using helper
function helper(node, low, high) {Helper function carries current valid range for node values
if (!node) return true;Empty subtree is valid BST
if (node.val <= low || node.val >= high) return false;Check if node violates BST property with current bounds
return helper(node.left, low, node.val) && helper(node.right, node.val, high);Recurse with updated bounds for left and right subtrees
TimeO(n)
SpaceO(h) where h is tree height due to recursion stack
Each node is visited once, and range checks are O(1), so linear time. Space depends on recursion depth.
💡 For n=20 nodes in a balanced tree, recursion depth is about 5, so space is small and time is efficient.
Interview Verdict: Accepted
This approach is efficient and commonly accepted in interviews.