The problem. Given the root of a binary tree, return true if it is a valid binary search tree: every node's left subtree holds only values less than the node, its right subtree only values greater, and both subtrees are BSTs too.
root = [2, 1, 3] -> true
root = [5, 1, 4, null, null, 3, 6] -> false (4 is in 5's right subtree)
root = [5, 1, 6, null, null, 3, 7] -> false (3 is in 5's right subtree)
root = [2, 2, 2] -> false (no duplicates: strictly less / greater)Checking only left.val < node.val < right.val at each node passes the tree above — and it's wrong. The rule is about whole subtrees. Two correct ways to enforce it: pass down the range each node must fit in, or check that the in-order walk is strictly increasing.
At each node, check that the largest value in its left subtree is smaller and the smallest value in its right subtree is bigger — then check both subtrees the same way.
function isValidBST(node) { if (node === null) return true; if (node.left !== null && max(node.left) >= node.val) return false; if (node.right !== null && min(node.right) <= node.val) return false; return isValidBST(node.left) && isValidBST(node.right);} function max(n) { // the largest value in this subtree let m = n.val; if (n.left !== null) m = Math.max(m, max(n.left)); if (n.right !== null) m = Math.max(m, max(n.right)); return m;} function min(n) { // the smallest value in this subtree let m = n.val; if (n.left !== null) m = Math.min(m, min(n.left)); if (n.right !== null) m = Math.min(m, min(n.right)); return m;}Time O(n²) in the worst case (every node scans its whole subtree), space O(h).
The root may be anything. Going left narrows the range from above (everything there must be below this node); going right narrows it from below. Each node just checks that it fits its range.
Each node carries the range its ancestors allow; one value outside it fails the tree.
function isValidBST(root) { const fits = (node, low, high) => { // every value here must be strictly between low and high if (node === null) return true; if (node.val <= low || node.val >= high) return false; return fits(node.left, low, node.val) && fits(node.right, node.val, high); }; return fits(root, -Infinity, Infinity);}Time O(n), space O(h). Java and C++ use 64-bit bounds because a node may hold Integer.MIN_VALUE or MAX_VALUE itself.
A binary tree is a BST exactly when its in-order walk is strictly increasing. Walk it and compare each value with the previous one.
function isValidBST(root) { let prev = null; const inorder = (node) => { if (node === null) return true; if (!inorder(node.left)) return false; if (prev !== null && node.val <= prev) return false; // not bigger than the value before it prev = node.val; return inorder(node.right); }; return inorder(root);}Time O(n), space O(h). It stops at the first value out of order.
[2, 2, 2] is not a BST under the strict rule.[2147483647] must be valid: don't use int bounds as "no limit".[5, 1, 6, null, null, 3, 7].