Description
Given the root of a binary tree, determine if it is a valid binary search tree (BST).
A valid BST is defined as follows:
- The left subtree of a node contains only nodes with keys strictly less than the node’s key.
- The right subtree of a node contains only nodes with keys strictly greater than the node’s key.
- Both the left and right subtrees must also be binary search trees.
Example 1:

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

Input: root = [5,1,4,null,null,3,6]
Output: false
Explanation: The root node’s value is 5 but its right child’s value is 4.
Constraints:
- The number of nodes in the tree is in the range
[1, 104]. -231 <= Node.val <= 231 - 1
Approach - Recursion
- It should be strictly less and greater so equal values not allowed
- we go left so we update the max to current value
Time: O(n) Space: O(n)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean isValidBST(TreeNode root) {
return valid(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean valid(TreeNode n, long min, long max) {
if (n == null) return true;
if (n.val <= min || n.val >= max) return false;
return valid(n.left, min, n.val) && valid(n.right, n.val, max);
}
}Primary Approach: Recursive Range DFS ( Time, Space)
Intuition
Checking only immediate children (node.left.val < node.val < node.right.val) is a classic trap because it misses ancestor constraints. Every node must fall strictly within a dynamic valid range (min, max) passed down from its parent and ancestors:
- Initialize the range boundaries using
Long.MIN_VALUEandLong.MAX_VALUEto cleanly handle node values that equalInteger.MIN_VALUEorInteger.MAX_VALUE. - Base Case: An empty subtree (
node == null) is valid, so returntrue. - Validation: If
node.val <= minornode.val >= max, the BST invariant is broken; returnfalse. - Subtrees:
- Left Subtree: Values must be strictly less than
node.valsetmax = node.val. - Right Subtree: Values must be strictly greater than
node.valsetmin = node.val.
- Left Subtree: Values must be strictly less than
class Solution {
public boolean isValidBST(TreeNode root) {
return isValid(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
private boolean isValid(TreeNode node, long min, long max) {
if (node == null) return true;
// Node value must lie strictly within (min, max)
if (node.val <= min || node.val >= max) return false;
// Left child max bound becomes node.val; Right child min bound becomes node.val
return isValid(node.left, min, node.val) && isValid(node.right, node.val, max);
}
}
Complexity
- Time Complexity: — Every node in the binary tree is visited once.
- Space Complexity: — Auxiliary call stack space bounded by tree height ( for balanced, for skewed).
Alternative Approach: Inorder Traversal ( Time, Space)
Intuition
An inorder traversal () of a valid BST must yield strictly increasing values:
- Maintain a
prevpointer tracking the previously visited node in theinordersequence. - Recursively visit the left subtree first.
- Check if
prev != null && node.val <= prev.val. If true, the tree is invalid. - Set
prev = nodeand recursively check the right subtree.
class Solution {
private TreeNode prev = null;
public boolean isValidBST(TreeNode root) {
return inorder(root);
}
private boolean inorder(TreeNode node) {
if (node == null) return true;
// 1. Visit left subtree
if (!inorder(node.left)) return false;
// 2. Validate current node against previous inorder value
if (prev != null && node.val <= prev.val) return false;
prev = node;
// 3. Visit right subtree
return inorder(node.right);
}
}
Complexity
- Time Complexity: — Every node is visited once in
inordersequence. - Space Complexity: — Call stack depth bounded by tree height .
Key Interview Discussion Points
- The Local Check Trap: Point out that checking only
node.leftandnode.rightfails. For example, in[5, 1, 6, null, null, 3, 7], node3is locally valid as the left child of6, but invalid because it resides in the right subtree of5. - Integer Boundary Edge Case: Mention that using
longparameters (Long.MIN_VALUE,Long.MAX_VALUE) prevents overflow/underflow failures when tree nodes contain values equal toInteger.MIN_VALUEorInteger.MAX_VALUE.
Easy Memory Rule
“Pass
(min, node.val)to Left Subtree Pass(node.val, max)to Right Subtree UseLongbounds for edge cases!”