Pattern #38

Binary Search Trees

Important interview questions, thinking patterns, Inorder = Sorted rule, BST Search & Pruning, 3 cases of Deletion, and Go templates.

Must Solve

16 core questions — solve these first.

  1. 1.Search in a Binary Search Tree
    easy
  2. 2.Validate Binary Search Tree
    medium
  3. 3.Kth Smallest Element in a BST
    medium
  4. 4.Lowest Common Ancestor of a BST
    medium
  5. 5.Insert into a Binary Search Tree
    medium
  6. 6.Delete Node in a BST
    medium
  7. 7.Convert Sorted Array to Binary Search Tree
    easy
  8. 8.Minimum Absolute Difference in BST
    easy
  9. 9.Two Sum IV — Input is a BST
    easy
  10. 10.Range Sum of BST
    easy
  11. 11.BST Iterator
    medium
  12. 12.Recover Binary Search Tree
    medium
  13. 13.Trim a Binary Search Tree
    medium
  14. 14.Balance a Binary Search Tree
    medium
  15. 15.Convert BST to Greater Tree
    medium
  16. 16.Construct BST from Preorder Traversal
    medium

Also Important

9 more questions worth practicing.

  1. 17.Find Mode in Binary Search Tree
    easy
  2. 18.Increasing Order Search Tree
    easy
  3. 19.Closest Binary Search Tree Value
    easy
  4. 20.Inorder Successor in BST
    medium
  5. 21.Inorder Predecessor in BST
    medium
  6. 22.Unique Binary Search Trees
    medium
  7. 23.Unique Binary Search Trees II
    medium
  8. 24.Serialize and Deserialize BST
    medium
  9. 25.Split BST
    medium

How to Think

  1. Tree has ordering property?Binary Search Tree (BST)
  2. Need search for value?val < node -> go Left, val > node -> go Right
  3. Need sorted values from BST?Inorder Traversal (Left-Root-Right)
  4. Need Kth smallest?Inorder + Count to K
  5. Need validate BST?Lower Bound < Node < Upper Bound
  6. Need LCA in BST?Order split point (both < node -> left, both > node -> right)

Go BST Code Templates

Iterative BST Search & LCA in Go

type TreeNode struct {
    Val   int
    Left  *TreeNode
    Right *TreeNode
}

// Iterative BST Search: O(H) time, O(1) space
func searchBST(root *TreeNode, target int) *TreeNode {
    for root != nil {
        if root.Val == target {
            return root
        }
        if target < root.Val {
            root = root.Left
        } else {
            root = root.Right
        }
    }
    return nil
}

// Lowest Common Ancestor in a BST using Ordering
func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    for root != nil {
        if p.Val < root.Val && q.Val < root.Val {
            root = root.Left
        } else if p.Val > root.Val && q.Val > root.Val {
            root = root.Right
        } else {
            return root // Split point is the LCA!
        }
    }
    return nil
}

👉 Total Time: O(H) | Space: O(1)

The Golden Rule: BST + Inorder = Sorted Array

Inorder Traversal (Left -> Root -> Right) of any valid Binary Search Tree visits nodes in strictly ascending sorted order!

// Find Kth Smallest Element in a BST
func kthSmallest(root *TreeNode, k int) int {
    count := 0
    result := 0

    var inorder func(node *TreeNode)
    inorder = func(node *TreeNode) {
        if node == nil || count >= k {
            return
        }

        inorder(node.Left)

        count++
        if count == k {
            result = node.Val
            return
        }

        inorder(node.Right)
    }

    inorder(root)
    return result
}

👉 Time: O(H + K) | Space: O(H) recursion stack (no need to store full array!)

Delete Node in a BST (3 Cases)

1. Leaf Node: Simply return nil to remove it.

2. One Child: Replace node with its non-nil child (node.Left or node.Right).

3. Two Children: Find the Inorder Successor (smallest value in right subtree: go Right once, then Left as far as possible). Copy successor value into node, then recursively delete successor in right subtree!

func deleteNode(root *TreeNode, key int) *TreeNode {
    if root == nil {
        return nil
    }

    if key < root.Val {
        root.Left = deleteNode(root.Left, key)
    } else if key > root.Val {
        root.Right = deleteNode(root.Right, key)
    } else {
        // Found node to delete!
        if root.Left == nil {
            return root.Right
        }
        if root.Right == nil {
            return root.Left
        }

        // 2 Children case: find Inorder Successor (min in Right subtree)
        curr := root.Right
        for curr.Left != nil {
            curr = curr.Left
        }
        root.Val = curr.Val
        root.Right = deleteNode(root.Right, curr.Val)
    }
    return root
}
Visual Memory Rule
Smaller -> Go Left  |  Larger -> Go Right
BST + Inorder = Strictly Sorted Array
Validate BST = Lower Bound < Node.Val < Upper Bound
LCA in BST = First node where targets p and q split
Delete Node (2 Children) -> Replace with Inorder Successor (Min of Right Subtree)

💡 Golden Rule: "Use the BST ordering to eliminate the part of the tree that cannot contain your answer."

Common Interview Mistakes

1. Checking Only Direct Children

Only checking left < node && right > node fails! Must carry ancestor bounds [minVal, maxVal] down the subtree.

2. Assuming BST Is Balanced

Skewed BST (e.g. inserting 1,2,3,4,5) has height O(N)! Say time complexity is O(H) where H = O(log N) balanced.

3. Searching Both Sides

In a valid BST, do NOT search both subtrees recursively! Use the ordering to prune one entire side.

4. Wrong Deletion Logic

When deleting a node with 2 children, copy the Inorder Successor value, then delete that successor node recursively from the right subtree.

Interview Rules

  1. 1. Ordered binary tree? → BST
  2. 2. Smaller target? → Go Left (target < node.Val)
  3. 3. Larger target? → Go Right (target > node.Val)
  4. 4. Sorted elements needed? → Inorder Traversal (Left - Root - Right)
  5. 5. Validate BST? → Pass lower < node.Val < upper bounds downward
  6. 6. LCA in BST? → First split point node where p and q diverge
  7. 7. Delete node with 2 children? → Replace with Inorder Successor (minimum of right subtree)
  8. 8. Overall Complexity → Search/Insert/Delete: O(H) (O(log N) balanced, O(N) skewed)

Small Rules

  1. Rule 1: BST ordering applies to the entire left/right subtree, not just immediate children.
  2. Rule 2: Inorder traversal of a BST always yields strictly sorted values.
  3. Rule 3: Search, Insert, and Delete run in O(H) time.
  4. Rule 4: Inorder Successor is the smallest value in the right subtree.
  5. Rule 5:Range queries prune impossible subtrees (skip Left if node.Val < low, skip Right if node.Val > high).

Production Thinking

Ordered In-Memory Maps & SetsSelf-balancing Red-Black trees powering C++ std::map & Java TreeMap

Range Queries (Timestamps/Prices)Filtering score/price intervals efficiently without full scans

Database Indexing (B-Tree / B+Tree)Ordered disk page search trees pruning search space in Postgres & MySQL

Priority / Order MaintenanceMaintaining dynamic ordered lists during frequent inserts & deletions

Remember This

BST
Left            → Smaller
Right           → Larger
Search          → Choose one side
Inorder         → Sorted array
Validate        → Lower < Node < Upper
Kth Smallest    → Inorder + Count
LCA             → Find split point
Delete 2 Ch.    → Successor / Predecessor
Balanced        → O(log N)
Skewed          → O(N)

💡 Golden Rule: "Use the BST ordering to eliminate the part of the tree that cannot contain your answer."