98. Validate Binary Search Tree
mediumAsked at AtlassianValidate Binary Search Tree is an Atlassian classic for testing whether you understand the recursive invariant of a BST. Return true if a given binary tree is a valid BST. The naive 'check children' answer is wrong, and Atlassian uses this exact gap to grade rigorous thinkers.
By Alex Chen, Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in Atlassian loops.
- Glassdoor (2026-Q1)— Atlassian SWE-II onsite reports cite Validate BST as a recurring tree problem in round 2.
- Blind (2025-09)— Atlassian threads repeatedly cite this as the problem that filters out 'looks-correct-but-isn't' candidates.
Problem
Given the root of a binary tree, determine if it is a valid binary search tree (BST). A valid BST is defined as: 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; and both the left and right subtrees must also be binary search trees.
Constraints
The number of nodes in the tree is in the range [1, 10^4].-2^31 <= Node.val <= 2^31 - 1
Examples
Example 1
root = [2,1,3]trueExample 2
root = [5,1,4,null,null,3,6]falseExplanation: The root node's value is 5 but its right child's value is 4.
Approaches
1. Naive child-comparison (broken)
At each node, check left.val < val < right.val and recurse.
- Time
- O(n)
- Space
- O(h)
function isValidBSTBroken(root) {
if (!root) return true;
if (root.left && root.left.val >= root.val) return false;
if (root.right && root.right.val <= root.val) return false;
return isValidBSTBroken(root.left) && isValidBSTBroken(root.right);
}Tradeoff: EXPLICITLY WRONG. Tree [5,1,4,null,null,3,6] passes this check (5>1, 5<4 fails — wait, this catches that case). The real failure: [10,5,15,null,null,6,20] — 15>10 OK, 6<15 OK locally, but 6<10 violates ancestor. Show this code first to demonstrate you understand WHY it's wrong, then fix.
2. Range propagation (canonical)
Pass (lo, hi) bounds down the recursion. At each node, val must be strictly between lo and hi; recurse left with hi=val, right with lo=val.
- Time
- O(n)
- Space
- O(h) recursion
function isValidBST(root) {
const validate = (node, lo, hi) => {
if (!node) return true;
if (lo !== null && node.val <= lo) return false;
if (hi !== null && node.val >= hi) return false;
return validate(node.left, lo, node.val) && validate(node.right, node.val, hi);
};
return validate(root, null, null);
}Tradeoff: The Atlassian-canonical answer. Carries the ancestor constraint via the bounds. Use null sentinels (not -Infinity / Infinity) because LeetCode's val range includes those numerically; null cleanly means 'no bound'.
3. In-order traversal monotonicity check
In-order traversal of a BST visits nodes in strictly ascending order. Walk in-order; fail if any node's value is <= the previous.
- Time
- O(n)
- Space
- O(h)
function isValidBSTInorder(root) {
let prev = null;
const inorder = (node) => {
if (!node) return true;
if (!inorder(node.left)) return false;
if (prev !== null && node.val <= prev) return false;
prev = node.val;
return inorder(node.right);
};
return inorder(root);
}Tradeoff: Elegant — uses the defining property of BST in-order traversal. Closure over prev is the subtle part; some interviewers prefer this version because it's a smaller mental model. Either this or range-propagation passes; mention both.
Atlassian-specific tips
Atlassian explicitly grades whether you spot WHY the naive child-comparison fails. Spend 30 seconds writing the broken version and constructing the counterexample tree [10,5,15,null,null,6,20] aloud — the interviewer sees you understand the bug, not just the fix. Both range-propagation and in-order pass; range is more defensible if asked 'how do you avoid global state?', in-order is more elegant. Mention both.
Common mistakes
- Using <= where < is required (or vice versa) — the LeetCode spec is strictly less / strictly greater, so equal values invalidate.
- Initializing bounds with Number.MIN_SAFE_INTEGER / MAX_SAFE_INTEGER — those values can legitimately appear in the tree. Use null sentinels and check for null before comparing.
- On the in-order version, declaring prev inside the function — it resets to null every call. Use a closure or wrapper object.
Follow-up questions
An interviewer at Atlassian may pivot to one of these next:
- Recover Binary Search Tree (LeetCode 99) — two nodes are swapped; find and swap them back. In-order traversal finds the dips.
- Convert Sorted Array to BST (LeetCode 108) — opposite direction; build a balanced BST.
- What if the tree's values are floats and equality is OK? Switch to <= and >= in the recursion; the rest is unchanged.
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Range or in-order at Atlassian?
Either passes. Lead with range-propagation because it generalizes to more constraints (e.g., min-distance constraints) without restructuring. Mention in-order as 'and there's a more elegant traversal-based variant'. The interviewer will probably let you pick.
Why is null sentinel safer than +-Infinity?
Because LeetCode's val range is [-2^31, 2^31 - 1] in integer mode, and floats outside that range can compare incorrectly. null with an explicit guard expresses 'no bound' unambiguously. Use it.
Free learning resources
Curated free links for this problem.
Practice these live with InterviewChamp.AI
Drill Validate Binary Search Tree and other Atlassian interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.
Practice these live with InterviewChamp.AI →