Given the root of a binary tree, determine if it is a valid binary search tree (BST).
A valid BST is defined as follows:
Input: root = [2,1,3]
Output: true
Tree:
2
/ \
1 3
Valid BST: 1 < 2 < 3 ✓
Input: root = [5,1,4,null,null,3,6]
Output: false
Tree:
5
/ \
1 4
/ \
3 6
Invalid: Node 4 is in right subtree of 5, but 4 < 5 ✗
Input: root = [5,4,6,null,null,3,7]
Output: false
Tree:
5
/ \
4 6
/ \
3 7
Invalid: Node 3 is in right subtree of 5, but 3 < 5 ✗
Common Mistake: Just checking left.val < node.val < right.val is NOT enough!
Example: [5,1,4,null,null,3,6] - Node 3 is in right subtree of 5 but 3 < 5.
Key Insight: Every node must satisfy a range constraint:
We pass down valid ranges and check if each node falls within its range.
This is a DFS with Range Validation problem:
Helper Function: isValid(node, min_val, max_val)
For Each Node:
min_val < node.val < max_valisValid(left, min_val, node.val)isValid(right, node.val, max_val)Initial Call: isValid(root, -∞, +∞)
Why this works:
BST property: In-order traversal produces sorted sequence!
def inorder(node):
if not node: return True
if not inorder(node.left): return False
if node.val <= prev: return False
prev = node.val
return inorder(node.right)
If in-order is strictly increasing → valid BST
Time: O(n) where n = number of nodes
Space: O(h) where h = height
1class TreeNode {
2 int val;
3 TreeNode left;
4 TreeNode right;
5 TreeNode() {}
6 TreeNode(int val) { this.val = val; }
7 TreeNode(int val, TreeNode left, TreeNode right) {
8 this.val = val;
9 this.left = left;
10 this.right = right;
11 }
12}
13
14class Solution {
15 public boolean isValidBST(TreeNode root) {
16 return isValid(root, null, null);
17 }
18
19 private boolean isValid(TreeNode node, Integer minVal, Integer maxVal) {
20 // Base case: null node is valid
21 if (node == null) {
22 return true;
23 }
24
25 // Check if current node violates BST property
26 if ((minVal != null && node.val <= minVal) ||
27 (maxVal != null && node.val >= maxVal)) {
28 return false;
29 }
30
31 // Validate left subtree (must be < node.val)
32 // Validate right subtree (must be > node.val)
33 return isValid(node.left, minVal, node.val) &&
34 isValid(node.right, node.val, maxVal);
35 }
36}
37