Home › DSA Patterns › Binary Search Trees
B

Binary Search Trees

Master one idea and half the "tree" problems in interviews stop being scary. That idea is the BST invariant, and once you feel it in your bones you stop writing random recursion and start writing code that is correct the first time. Most candidates who freeze on tree questions never built the right picture: they poke at children, lose track of what they actually have, and 20 minutes later they are debugging a solution that was never going to work. Here is the picture that fixes that.

DSA PatternsMedium11 min read
Who asks this, and how oftenInterview frequency: High

Most asked at Amazon. Here is how often this pattern shows up in each company's coding rounds.

Amazon
82
Microsoft
80
Google
78
Meta
72
Apple
70
Relative frequency index from 0 to 100, based on commonly reported interview experiences. Use it as a guide to where this pattern pays off most, not an exact count.

If you remember five things

The whole topic in one glance. Everything below is the defense of these five calls.

  1. The invariant is whole-subtree. Every node beats its entire left subtree and loses to its entire right subtree, not just its two children. That word "entire" is where the bugs live.
  2. In-order walk is a sorted array. Left, node, right reads the values out smallest to largest, every time. K-th smallest, validation, Recover BST all lean on this one fact.
  3. Two views, pick one in 30 seconds. "Find / closest / range" wants the pruning view (throw away half the tree). "K-th / is this sorted" wants the flattened view (in-order).
  4. The template is one shape. Stand at a node, compare, go left or right. Search, insert, and LCA are all this walk. Cost is O(height), not O(n).
  5. Balance is the catch. O(log n) only holds if the tree is balanced. Insert sorted data and it degrades to a linked list at O(n). Say this out loud before they ask.

1The mental model (what this really is)#

A binary search tree is a binary tree with one promise attached to every single node.

Everything in my left subtree is smaller than me. Everything in my right subtree is larger than me.

  • Not just my immediate children. My entire left subtree and my entire right subtree.
  • That word "entire" is where most bugs live. Section 4 shows exactly how ignoring it produces a validator that approves trees it should reject.

The insight that changes everything: a BST is a sorted array that someone folded up.

  • Walk the tree left, then node, then right and the values come out in sorted order. Every time.
  • That walk is called in-order traversal.
  • It is the secret weapon behind a surprising number of problems: k-th smallest, validation, finding the two swapped nodes in Recover BST. All of them.

So when you see a BST, hold two thoughts at once.

  • Search structure: I can throw away half the tree at each step, so my search costs O(height), not O(n).
  • Sorted list: if I walk it in-order, it is already sorted.
The skill the interviewer is grading

Different problems want different views. "Find a value" or "closest to a target" wants the pruning view. "K-th smallest" or "is this sorted" wants the flattened view. Picking the right one in the first 30 seconds is most of the job, and it is scored before you write a line.

2How to recognize it (the signals in a problem)#

You are looking at a BST problem when any of these fire.

  • The problem literally says "binary search tree." Easy tell, but read the constraint: the trick is usually "use the ordering, do not treat it as a plain binary tree." If an O(n) scan would solve it, the BST label is a hint that O(height) is the expected answer.
  • You need the k-th smallest or k-th largest. That is in-order traversal with a counter, stopping at the k-th visit.
  • You need to validate a tree is a valid BST. Classic trap, covered in section 4.
  • You need find, insert, or delete on a sorted structure. Target O(height), which is O(log n) on a balanced tree.
  • The words "closest value," "range sum," "elements between low and high," or "successor / predecessor" appear. All exploit ordering so you can prune whole subtrees instead of visiting them.

The tell that separates strong from average:

  • The average candidate solves a BST problem the way they solve a plain binary tree, by visiting every node.
  • The strong candidate asks "can I skip a whole subtree here?"
  • If the answer was yes and you still visited everything, you turned an O(log n) problem into O(n) and the interviewer noticed.
From the interviewer's chair

On Range Sum of BST, if the current node is below the low bound, the entire left subtree is also below it, so I want to see you never recurse left. That one prune is the difference between a passing answer and a brilliant one. I am watching your hands: do you reach left out of habit, or do you stop and ask whether you can skip it?

3The template (how it works, with pseudocode)#

Almost every BST operation is the same shape: stand at a node, compare, go left or right. Here is the core search.

function search(node, target):
    while node is not null:
        if target == node.val:
            return node
        else if target < node.val:
            node = node.left     # target must be on the left
        else:
            node = node.right    # target must be on the right
    return null
  • That is the whole engine.
  • It is iterative, so O(1) extra space, no recursion stack.

Insert is the same walk. When you fall off the tree (hit null), that empty spot is where the new value belongs.

function insert(node, val):
    if node is null:
        return new Node(val)
    if val < node.val:
        node.left = insert(node.left, val)
    else:
        node.right = insert(node.right, val)
    return node

And the one to memorize cold, in-order traversal, because it gives you sorted output.

function inorder(node, visit):
    if node is null: return
    inorder(node.left, visit)
    visit(node.val)              # values arrive in sorted order
    inorder(node.right, visit)

Three moves, and you can derive the rest at the whiteboard:

  • Compare and branch.
  • Recurse down the one side you chose.
  • Walk in-order for a sorted view.
A thing to say out loud, not silently assume

The recursive in-order above uses O(h) stack and always walks to the end. If the problem wants an early stop (k-th smallest) or a one-value-at-a-time stream (BST Iterator), rewrite it as an iterative in-order with an explicit stack so you can pause after each visit. Candidates who ship the recursive version for BST Iterator get caught the moment the interviewer asks for the next value on demand.

4A worked example (walk through one problem step by step)#

Let me take a problem that looks annoying and show how the BST view makes it short: validate whether a binary tree is a valid BST. This is the single most asked BST question I see, so get it cold.

The naive attempt (I see it constantly):

  • Check that each node's left child is smaller and right child is larger.
  • Recurse. Done.
  • It is wrong. Here is why.
        10
       /  \
      5    15
          /  \
         6    20

Figure. Look at node 6. Its parent 15 is larger, so the local "my children are in order" check passes. But 6 sits in the right subtree of 10, so it must exceed 10, and it does not. The tree is invalid and the naive check approves it. This is the exact case the interviewer is watching for.

The real rule is the invariant from section 1.

  • Everything in the right subtree of 10 must exceed 10.
  • So each node is not just bounded by its parent. It is bounded by a range that tightens as you descend.
Pause before the code: as you descend, when do you set a new lower bound, and when a new upper bound?
Reveal the answer
Going left sets a new upper bound (the current node's value), because everything down there must be smaller. Going right sets a new lower bound, because everything down there must be larger. The floor and ceiling ratchet inward one step at a time. The root starts with no limits: the range (negative infinity, positive infinity).
function isValid(node, low, high):
    if node is null:
        return true
    if node.val <= low or node.val >= high:
        return false
    return isValid(node.left, low, node.val)
       and isValid(node.right, node.val, high)

isValid(root, -infinity, +infinity)

Trace it on the bad tree:

  • Root 10, range (-inf, +inf). Fine. Go right with range (10, +inf).
  • Node 15, range (10, +inf). Fine. Go left with range (10, 15).
  • Node 6, range (10, 15). Is 6 greater than 10? No, 6 is below the low bound. Return false.

  • The bug the naive version missed is caught instantly, because we carried 10 down as a hard floor.

  • Runs in O(n) time (each node checked once) and O(h) stack space.

A second, even cleaner way to explain it:

  • Do an in-order traversal and check the output is strictly increasing.
  • Keep one "previous value" variable. The moment the current value is not strictly greater, return false.
  • If the sorted walk ever goes flat or backward, it is not a valid BST.
Why mentioning both approaches earns points

Say "the range method is explicit about bounds, the in-order method just checks the sorted invariant directly" and you have shown you understand the two views of a BST, not one trick. That one sentence reads as fluency.

5Variations and gotchas (what the interviewer throws next)#

A few patterns show up again and again once you know the base.

K-th smallest element.

  • In-order traversal, stop at the k-th visit. You do not finish the walk.
  • Iterative in-order with an explicit stack lets you stop early and stay O(h) extra space.
  • Time is O(h + k): you descend once, then pop k times.

Lowest common ancestor in a BST.

  • This is a BST-only shortcut. Do not drag in the general-tree LCA (O(n), full recursion).
  • Walk down from the root: both targets smaller than the current node, go left. Both larger, go right.
  • The moment they split (one smaller, one larger, or one equals the node), you are standing on the LCA.
  • O(height), iterative, no recursion stack. Solve it the general-tree way and the interviewer asks "but it is a BST, can you do better?", so start with the better answer.

Insert and delete.

  • Insert is the same walk as search until you hit null. Easy.
  • Delete is the one that trips people:
  • Leaf: null it out.
  • One child: splice the child up into its place.
  • Two children (the hard case): replace the node's value with its in-order successor (smallest value in its right subtree: go right once, then left until you cannot), then delete that successor from its old spot.
  • Practice the two-child case by hand. The "then delete the successor" half is where people forget a step, and it is a favorite follow-up.

Duplicates.

  • Interviewers love to ask. Decide a convention (go right on equal, say) and state it out loud before you write code.
  • Your validation bounds must then use strict vs non-strict comparison consistently, or you get subtle wrong answers that pass small tests and fail the one with a repeated value.

The balance problem.

  • A BST only gives O(log n) if it is balanced.
  • Insert 1, 2, 3, 4, 5 in order and you get a straight line, a linked list wearing a tree costume, and every operation becomes O(n).
  • If the interviewer stresses worst case, name self-balancing trees (AVL, red-black) or at least that the structure can degrade. You rarely implement balancing in an interview, but naming it earns credit and costs one sentence.

If your BST search is O(n), you are not using the BST. That is the whole point of the question.

6Complexity#

For a BST with n nodes and height h (roughly log n when balanced):

Operation Average Worst case (degenerate)
Search O(log n) O(n)
Insert O(log n) O(n)
Delete O(log n) O(n)
In-order traversal O(n) O(n)
k-th smallest O(h + k) O(n)

Reading the table:

  • Space: recursion uses O(h) stack. Balanced tree, O(log n). Degenerate, O(n).
  • The full traversal always touches all n nodes, so you cannot beat O(n) there. Targeted searches should be O(h).
  • If your "search" is O(n), you are not using the BST property.

The honest trade-off (say this out loud):

  • A BST gives ordered operations a hash set cannot: range queries, successor, predecessor, k-th smallest, "all values in [low, high]".
  • A hash set gives O(1) average lookup but zero order, so it cannot answer "what is the next-largest key" without scanning everything.
  • Reach for a BST when order matters, a hash set when it does not. Saying that tells the interviewer you picked the structure on purpose.

7Mistakes that cost people the round#

Checking only immediate children for validity.

  • The number one BST mistake, the one from section 4.
  • Carry a min/max range down the tree instead. We walked through exactly why the local check passes the invalid tree with node 6.

Using the wrong infinity.

  • Validating with integer bounds, a node holding the maximum possible integer breaks naive comparisons (you cannot set the bound one higher).
  • Use open bounds and pass the node's value itself as the new bound, or use a nullable "previous value" with in-order so there is no sentinel at all. State your assumption about the value range.

Treating a BST like a generic binary tree.

  • Visit every node to find one value and you threw away the ordering.
  • The interviewer handed you a sorted structure on purpose. Ignoring it reads as "did not notice the input."

Forgetting the degenerate case.

  • Say "this assumes the tree is reasonably balanced, worst case it degrades to O(n)." Five seconds, and it signals maturity about real inputs.

Botching two-child deletion.

  • Get the in-order successor logic right, and actually remove the successor from its old spot after copying its value up.
  • Dry-run it on paper before you claim it works. This is the follow-up that separates "memorized it" from "understands it."

Recursion with no base case for null.

  • Half of tree bugs are a missing if node is null.
  • Write that line first, always, before anything else in the function.
Follow-ups the interviewer will ask (and your answers)
"Your validator passes a node whose parent check is fine but a grandparent is violated. Fix it."
That is the local-check bug. I carry a (low, high) range down the recursion instead of comparing to the parent. Going left tightens the upper bound to the current node's value, going right tightens the lower bound. A node outside its inherited range fails immediately, so a grandparent violation like node 6 under root 10 is caught.
"Give me the k-th smallest without walking the whole tree."
Iterative in-order with an explicit stack: push left spine, pop a node (that is the next smallest), decrement k, if k hits zero return it, otherwise move to the node's right child and repeat. I stop the instant I hit the k-th visit, so it is O(h + k) time and O(h) space, not a full O(n) walk.
"It is a BST, so can you do LCA better than the general-tree version?"
Yes. Walk down from the root: if both targets are smaller, go left, if both larger, go right, otherwise they split at the current node and that is the LCA. O(height), iterative, no recursion stack, because the ordering tells me which way to go without exploring both sides.
"Delete a node with two children. Walk me through it."
Replace the node's value with its in-order successor, the smallest value in its right subtree, which I find by going right once then left until I cannot. Then I delete that successor from its old spot, which is itself an easy delete because it has at most a right child. Skipping that second delete leaves a duplicate, which is the classic slip.
"What if the input is sorted and you insert it in order?"
You get a degenerate tree, a straight line, and every operation becomes O(n). That is the balance problem. In a real system I would reach for a self-balancing tree (AVL or red-black) that rotates to keep height at O(log n). In an interview I name the degradation and the fix even if I do not implement the rotations.

8Your practice path (problems you can now solve)#

Do these in order. Names only, go solve them yourself. That is where the learning happens.

Warm up (Easy):

  • Search in a Binary Search Tree
  • Minimum Absolute Difference in BST
  • Range Sum of BST
  • Convert Sorted Array to Binary Search Tree

Core (Medium), this is where interviews live:

  • Validate Binary Search Tree
  • Kth Smallest Element in a BST
  • Lowest Common Ancestor of a Binary Search Tree
  • Insert into a Binary Search Tree
  • Delete Node in a BST
  • Binary Search Tree Iterator
  • Convert BST to Greater Tree

Stretch (Hard):

  • Recover Binary Search Tree
  • Count of Smaller Numbers After Self (BST as a counting structure)
  • Serialize and Deserialize BST

How to know you are ready:

  • Do the Core list cold, narrating the two views (search structure and sorted-when-walked) as you go.
  • Do not skip Delete Node and BST Iterator because they feel fiddly. Those are the two that most often show up as the "now make it harder" follow-up.

9Where this shows up#

BST questions are bread and butter at companies that lean algorithmic.

  • Google, Meta, Amazon, and Microsoft all pull from the Core list, especially Validate BST, Kth Smallest, and LCA.
  • Expect them in the phone screen and the first onsite round, often as the warm-up before a harder graph or dynamic-programming question.
  • Startups borrowing FAANG-style loops use them the same way: the opener that confirms you can write clean recursion under light pressure before they turn up the heat.
  • BST Iterator in particular is a favorite because it tests whether you really understand in-order traversal or just memorized it. You cannot fake the "pause between values" part with a copied snippet.

What you can now explain in the room

  • Why the BST invariant is about whole subtrees, not just immediate children.
  • Why an in-order walk reads the tree out in sorted order, and which problems that unlocks.
  • How to validate a BST two ways: a descending (low, high) range, or a strictly-increasing in-order check.
  • Why search, insert, and LCA are all the same compare-and-branch walk at O(height).
  • How two-child deletion works, including deleting the in-order successor from its old spot.
  • When a BST degrades to O(n), and when to pick a BST over a hash set in the first place.

Want to see exactly which of these pop up where? Check the company guides to map this pattern to the rounds you are actually interviewing for.

Get a prep plan built around your Binary Search Trees interview

Tell us the role and your interview date. We will send back a dated, day by day plan. Free.

Thanks. Check your inbox, your Binary Search Trees prep plan is on the way.