Validate Binary Search Tree medium
Problem Statement
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 less than the node's key.
- The right subtree of a node contains only nodes with keys 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.
Steps
- Recursive Approach: We'll use a recursive helper function to traverse the tree.
- In-order Traversal Logic: A BST, when traversed in-order (left, root, right), will produce a sorted sequence. We'll leverage this property. We'll maintain a variable to track the previous node's value during in-order traversal.
- Base Case: If the current node is null, we're done with that branch.
- Recursive Steps:
- Recursively check the left subtree.
- If the left subtree is invalid, return
false
. - Check if the current node's value is greater than the previous node's value (maintaining sorted order). If not, return
false
. - Update the
previous
node's value. - Recursively check the right subtree.
- If the right subtree is invalid, return
false
.
- Return
true
: If all checks pass, the tree is a valid BST.
Explanation
The key insight is that an in-order traversal of a BST yields a sorted sequence. Our recursive helper function simulates this traversal, keeping track of the previously visited node. If at any point the current node's value is not greater than the previous node's value, the sorted property is violated, and the tree is not a BST.
Code
class TreeNode {
val: number;
left: TreeNode | null;
right: TreeNode | null;
constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
this.val = val === undefined ? 0 : val;
this.left = left === undefined ? null : left;
this.right = right === undefined ? null : right;
}
}
function isValidBST(root: TreeNode | null): boolean {
let prev: number | null = null;
function isValidBSTHelper(node: TreeNode | null): boolean {
if (node === null) {
return true;
}
if (!isValidBSTHelper(node.left)) {
return false;
}
if (prev !== null && node.val <= prev) {
return false;
}
prev = node.val;
if (!isValidBSTHelper(node.right)) {
return false;
}
return true;
}
return isValidBSTHelper(root);
}
// Example usage:
const root1 = new TreeNode(2, new TreeNode(1), new TreeNode(3));
console.log(isValidBST(root1)); // true
const root2 = new TreeNode(5, new TreeNode(1), new TreeNode(4, new TreeNode(3), new TreeNode(6)));
console.log(isValidBST(root2)); // false
const root3 = new TreeNode(1, null, new TreeNode(2, null, new TreeNode(3)));
console.log(isValidBST(root3)); //false
Complexity
- Time Complexity: O(N), where N is the number of nodes in the tree. We visit each node once during the in-order traversal.
- Space Complexity: O(H), where H is the height of the tree. This is due to the recursive call stack. In the worst case (a skewed tree), H could be N, but in a balanced tree, H would be logâ‚‚N.