Skip to content
mlmentorship

Validate Binary Search Tree

Check whether every node follows all BST ordering rules.

Published · 6 min read ·Core ·Mixed

30-second answer map

Visual first · depth when needed

Validate each node against the complete interval inherited from every ancestor.

Preparing the visual…

ML breadth · active recall

Practice before you read

8 minutes. Explain the mechanism, why it works, when it fails, and one alternative.

How practice works

ML breadth · closed-book attempt

Validate Binary Search Tree

Explain the mechanism, why it works, when it fails, and one alternative.

08:00recommended time

Closing or reloading clears the scratchpad. Only score, weak rubric dimensions, attempt count, and retry date can be stored locally.

Check whether every node follows all BST ordering rules.

Start with the concrete trace below. It shows the state the algorithm must carry as it runs.

Problem trace

Validate Binary Search Tree: Validate each node against the complete interval inherited from every ancestor.

Input and goalCheck whether every node follows all BST ordering rules.
Call valid(5, -inf, inf)The root 5 satisfies -inf < 5 < inf, so recursively validate its left subtree before its right subtree.
5check -inf < 5 < inf/\17/\48
inputtree=[5,1,7,null,null,4,8]activeCheckcheck -inf < 5 < infstackvalid(5,-inf,inf)

Recognize it
BST validity applies against every ancestor, so a local parent-child comparison is insufficient and each recursive call must carry the legal value interval.
Keep true
At valid(node, low, high), every ancestor constraint is summarized by low < node.val < high; the left call tightens high and the right call tightens low.
Reuse it
When a recursive descendant must satisfy all ancestor decisions, summarize those decisions as constraints in the call state rather than rechecking only the parent.
Read it this way: The root 5 satisfies -inf < 5 < inf, so recursively validate its left subtree before its right subtree. Step through the frames to watch the state change. The last frame shows the answer or the stopping condition.

Pattern: DFS with valid lower and upper bounds.

Simple idea: A node in a left subtree must be below every ancestor bound, not only its parent. Pass the allowed value range down the tree.

def is_valid_bst(root: TreeNode | None) -> bool:
   def valid(node: TreeNode | None, low: float, high: float) -> bool:
      if node is None:
         return True
      if not low < node.val < high:
         return False
      return valid(node.left, low, node.val) and valid(node.right, node.val, high)

   return valid(root, float("-inf"), float("inf"))

Cost: time and call-stack space.

The platform supplies TreeNode with val, left, and right; this snippet assumes that definition.