Engineering Notes
Home/Algorithms & Coding Interviews/Recursion & Trees/Binary Search Trees
Algorithms & Coding Interviews · Recursion & Trees

Binary Search Trees

A binary search tree keeps smaller keys left and larger keys right, so search, insert and order statistics walk a single path. Learn the operations, the correct way to validate a BST, how languages expose balanced trees, and watch range validation, k-th smallest and BST LCA animated.

🧮 Algorithms & Coding Interviews● Intermediate⏱ 18 min read▶ 3 interactive🛠️ 4 exercises

🎯 What you'll learn

  • Search, insert and delete in O(h)
  • Validating with inherited ranges (not just parent–child)
  • Inorder order statistics and balanced construction
  • Six LeetCode problems with animated walkthroughs

📚 Before you start

Part 1The Pattern

A binary search tree keeps an ordering invariant: everything in a node's left subtree is smaller, everything in its right subtree is larger. That turns search, insert and delete into a single walk down one path, O(h) for height h, and makes an inorder traversal produce sorted order. Interview questions test whether you can exploit that invariant (skip half the tree at every node) and whether you validate it correctly.

A BST with the valid range of each node
A BST with the valid range of each node

1Operations

typescript
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}
function _tree(level: (number | null)[]): TreeNode | null {
  if (!level.length || level[0] === null) return null;
  const root = new TreeNode(level[0]); const q: TreeNode[] = [root]; let i = 1;
  while (q.length && i < level.length) {
    const node = q.shift()!;
    if (i < level.length && level[i] !== null) { node.left = new TreeNode(level[i]!); q.push(node.left); }
    i++;
    if (i < level.length && level[i] !== null) { node.right = new TreeNode(level[i]!); q.push(node.right); }
    i++;
  }
  return root;
}
function _level(root: TreeNode | null): (number | null)[] {
  const out: (number | null)[] = []; const q: (TreeNode | null)[] = [root];
  while (q.length) { const n = q.shift()!; if (n) { out.push(n.val); q.push(n.left, n.right); } else out.push(null); }
  while (out.length && out[out.length - 1] === null) out.pop();
  return out;
}

function search(root: TreeNode | null, target: number): TreeNode | null {
  let node = root;
  while (node && node.val !== target) node = target < node.val ? node.left : node.right;
  return node;
}

function insert(root: TreeNode | null, val: number): TreeNode {
  if (!root) return new TreeNode(val);
  if (val < root.val) root.left = insert(root.left, val);
  else root.right = insert(root.right, val);
  return root;
}

function isValid(node: TreeNode | null, low = -Infinity, high = Infinity): boolean {
  if (!node) return true;
  if (!(low < node.val && node.val < high)) return false;
  return isValid(node.left, low, node.val) && isValid(node.right, node.val, high);
}

function bstOps(level: (number | null)[], x: number): any[] {
  const root = _tree(level);
  insert(root, x);
  return [search(root, x) !== null, isValid(root), _level(root)];
}
python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def _tree(level):
    if not level or level[0] is None:
        return None
    root = TreeNode(level[0]); q = [root]; i = 1
    while q and i < len(level):
        node = q.pop(0)
        if i < len(level) and level[i] is not None:
            node.left = TreeNode(level[i]); q.append(node.left)
        i += 1
        if i < len(level) and level[i] is not None:
            node.right = TreeNode(level[i]); q.append(node.right)
        i += 1
    return root

def _level(root):
    out, q = [], [root]
    while q:
        n = q.pop(0)
        if n:
            out.append(n.val); q.append(n.left); q.append(n.right)
        else:
            out.append(None)
    while out and out[-1] is None:
        out.pop()
    return out

def search(root, target):
    node = root
    while node and node.val != target:
        node = node.left if target < node.val else node.right
    return node

def insert(root, val):
    if not root:
        return TreeNode(val)
    if val < root.val:
        root.left = insert(root.left, val)
    else:
        root.right = insert(root.right, val)
    return root

def is_valid(node, low=float("-inf"), high=float("inf")):
    if not node:
        return True
    if not (low < node.val < high):
        return False
    return is_valid(node.left, low, node.val) and is_valid(node.right, node.val, high)

def bst_ops(level, x):
    root = _tree(level)
    insert(root, x)
    return [search(root, x) is not None, is_valid(root), _level(root)]
OperationBalanced BSTDegenerate (sorted inserts)
search / insert / deleteO(log n)O(n)
min / maxO(log n): walk left/rightO(n)
inorder (sorted) iterationO(n)O(n)
k-th smallestO(h + k), or O(log n) with subtree sizesO(n)

Delete has three cases: a leaf (remove it), one child (splice the child up), two children (replace the value with the inorder successor, the minimum of the right subtree, then delete that successor).

2Validating a BST Correctly

Checking only left.val < node.val < right.val is wrong: a node deep in the left subtree must also be smaller than every ancestor it sits to the left of. Pass a valid range (low, high) down the tree: going left tightens high to the parent's value, going right tightens low. Equivalently, an inorder traversal must be strictly increasing.

3Using the Invariant

  • Search-like problems (LCA in a BST, closest value, floor/ceiling): at each node decide left or right, so you only walk one path.
  • Order statistics (k-th smallest, two-sum in BST, recover swapped nodes): use inorder traversal, often iteratively so you can stop early.
  • Construction (sorted array → balanced BST): take the middle element as root, recurse on halves.

4Balanced BSTs and Sorted Containers

Real systems keep BSTs balanced with rotations: AVL trees (strict height balance) or red-black trees (looser, fewer rotations). You'll rarely implement one in an interview, but know what your language provides:

LanguageOrdered set / map
Pythonnone built in; bisect on a sorted list (O(n) insert), or sortedcontainers.SortedList
JavaScript / TypeScriptnone built in; a sorted array + binary search, or a library
C#SortedSet<T>, SortedDictionary<K,V> (red-black trees), SortedList<K,V> (array)
JavaTreeSet, TreeMap
Under the HoodWhy Databases Use B-Trees, Not BSTs▾

A BST node holds one key, so a million keys need about 20 levels, which means up to 20 random disk reads per lookup. A B-tree node holds hundreds of keys (one disk page), so the same million keys fit in about 3 levels. Same invariant, wider nodes: see databases/indexing-storage/02-b_tree.

⚠️ Common Pitfalls

  1. Validating only parent–child pairs instead of the full ancestor range.
  2. Using int min/max as sentinels when node values can equal them; use None/null or ±infinity.
  3. Duplicates: decide (and say) whether they go left, right, or are disallowed.
  4. Assuming O(log n) for an unbalanced BST; sorted inserts make it a linked list.
  5. Forgetting to return the (possibly new) root from recursive insert/delete.

📋 Quick Reference

text
search: while node and node.val != x: node = left if x < node.val else right
validate: f(node, low, high): low < val < high; left gets (low, val), right gets (val, high)
inorder of a BST = sorted order · delete with 2 children → inorder successor
O(h): log n balanced, n degenerate
Part 2Interview Problems

Six problems that exploit the BST invariant: one-path walks, range validation, inorder order statistics and balanced construction.

1Search in a Binary Search Tree (LeetCode 700)

🟢 Easy. Return the subtree rooted at the node with value val, or null.

text
root = [4,2,7,1,3], val = 2 → [2,1,3]

Approach. Walk down: go left if val is smaller than the current node, right if larger.

Complexity. O(h) time, O(1) space iteratively.

typescript
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}
function _tree(level: (number | null)[]): TreeNode | null {
  if (!level.length || level[0] === null) return null;
  const root = new TreeNode(level[0]); const q: TreeNode[] = [root]; let i = 1;
  while (q.length && i < level.length) {
    const node = q.shift()!;
    if (i < level.length && level[i] !== null) { node.left = new TreeNode(level[i]!); q.push(node.left); }
    i++;
    if (i < level.length && level[i] !== null) { node.right = new TreeNode(level[i]!); q.push(node.right); }
    i++;
  }
  return root;
}
function _level(root: TreeNode | null): (number | null)[] {
  const out: (number | null)[] = []; const q: (TreeNode | null)[] = [root];
  while (q.length) { const n = q.shift()!; if (n) { out.push(n.val); q.push(n.left, n.right); } else out.push(null); }
  while (out.length && out[out.length - 1] === null) out.pop();
  return out;
}

function searchBST(root: TreeNode | null, val: number): TreeNode | null {
  while (root && root.val !== val) root = val < root.val ? root.left : root.right;
  return root;
}
python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def _tree(level):
    if not level or level[0] is None:
        return None
    root = TreeNode(level[0]); q = [root]; i = 1
    while q and i < len(level):
        node = q.pop(0)
        if i < len(level) and level[i] is not None:
            node.left = TreeNode(level[i]); q.append(node.left)
        i += 1
        if i < len(level) and level[i] is not None:
            node.right = TreeNode(level[i]); q.append(node.right)
        i += 1
    return root

def _level(root):
    out, q = [], [root]
    while q:
        n = q.pop(0)
        if n:
            out.append(n.val); q.append(n.left); q.append(n.right)
        else:
            out.append(None)
    while out and out[-1] is None:
        out.pop()
    return out

def search_bst(root, val):
    while root and root.val != val:
        root = root.left if val < root.val else root.right
    return root

2Validate Binary Search Tree (LeetCode 98)

🟠 Medium. Return true if the tree is a valid BST (strictly smaller on the left, strictly larger on the right, for every ancestor).

text
[5,4,6,null,null,3,7] → false   (3 is in 5's right subtree but smaller than 5)

Approach. Pass the allowed open interval (low, high) down the tree. The left child inherits (low, node.val), the right child (node.val, high).

Complexity. O(n) time, O(h) stack.

typescript
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}
function _tree(level: (number | null)[]): TreeNode | null {
  if (!level.length || level[0] === null) return null;
  const root = new TreeNode(level[0]); const q: TreeNode[] = [root]; let i = 1;
  while (q.length && i < level.length) {
    const node = q.shift()!;
    if (i < level.length && level[i] !== null) { node.left = new TreeNode(level[i]!); q.push(node.left); }
    i++;
    if (i < level.length && level[i] !== null) { node.right = new TreeNode(level[i]!); q.push(node.right); }
    i++;
  }
  return root;
}
function _level(root: TreeNode | null): (number | null)[] {
  const out: (number | null)[] = []; const q: (TreeNode | null)[] = [root];
  while (q.length) { const n = q.shift()!; if (n) { out.push(n.val); q.push(n.left, n.right); } else out.push(null); }
  while (out.length && out[out.length - 1] === null) out.pop();
  return out;
}

function isValidBST(root: TreeNode | null): boolean {
  const ok = (node: TreeNode | null, low: number, high: number): boolean => {
    if (!node) return true;
    if (!(low < node.val && node.val < high)) return false;
    return ok(node.left, low, node.val) && ok(node.right, node.val, high);
  };
  return ok(root, -Infinity, Infinity);
}
python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def _tree(level):
    if not level or level[0] is None:
        return None
    root = TreeNode(level[0]); q = [root]; i = 1
    while q and i < len(level):
        node = q.pop(0)
        if i < len(level) and level[i] is not None:
            node.left = TreeNode(level[i]); q.append(node.left)
        i += 1
        if i < len(level) and level[i] is not None:
            node.right = TreeNode(level[i]); q.append(node.right)
        i += 1
    return root

def _level(root):
    out, q = [], [root]
    while q:
        n = q.pop(0)
        if n:
            out.append(n.val); q.append(n.left); q.append(n.right)
        else:
            out.append(None)
    while out and out[-1] is None:
        out.pop()
    return out

def is_valid_bst(root):
    def ok(node, low, high):
        if not node:
            return True
        if not (low < node.val < high):
            return False
        return ok(node.left, low, node.val) and ok(node.right, node.val, high)
    return ok(root, float("-inf"), float("inf"))

3Kth Smallest Element in a BST (LeetCode 230)

🟠 Medium. Return the k-th smallest value (1-indexed) in a BST.

text
[5,3,6,2,4,null,null,1], k = 3 → 3

Approach. Iterative inorder traversal visits values in sorted order; stop at the k-th visit. Follow-up: if the tree changes often and k-th queries are frequent, store subtree sizes in each node for O(h) queries.

Complexity. O(h + k) time, O(h) space.

typescript
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}
function _tree(level: (number | null)[]): TreeNode | null {
  if (!level.length || level[0] === null) return null;
  const root = new TreeNode(level[0]); const q: TreeNode[] = [root]; let i = 1;
  while (q.length && i < level.length) {
    const node = q.shift()!;
    if (i < level.length && level[i] !== null) { node.left = new TreeNode(level[i]!); q.push(node.left); }
    i++;
    if (i < level.length && level[i] !== null) { node.right = new TreeNode(level[i]!); q.push(node.right); }
    i++;
  }
  return root;
}
function _level(root: TreeNode | null): (number | null)[] {
  const out: (number | null)[] = []; const q: (TreeNode | null)[] = [root];
  while (q.length) { const n = q.shift()!; if (n) { out.push(n.val); q.push(n.left, n.right); } else out.push(null); }
  while (out.length && out[out.length - 1] === null) out.pop();
  return out;
}

function kthSmallest(root: TreeNode | null, k: number): number {
  const stack: TreeNode[] = [];
  let node = root;
  while (true) {
    while (node) { stack.push(node); node = node.left; }
    node = stack.pop()!;
    if (--k === 0) return node.val;
    node = node.right;
  }
}
python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def _tree(level):
    if not level or level[0] is None:
        return None
    root = TreeNode(level[0]); q = [root]; i = 1
    while q and i < len(level):
        node = q.pop(0)
        if i < len(level) and level[i] is not None:
            node.left = TreeNode(level[i]); q.append(node.left)
        i += 1
        if i < len(level) and level[i] is not None:
            node.right = TreeNode(level[i]); q.append(node.right)
        i += 1
    return root

def _level(root):
    out, q = [], [root]
    while q:
        n = q.pop(0)
        if n:
            out.append(n.val); q.append(n.left); q.append(n.right)
        else:
            out.append(None)
    while out and out[-1] is None:
        out.pop()
    return out

def kth_smallest(root, k):
    stack, node = [], root
    while True:
        while node:
            stack.append(node); node = node.left
        node = stack.pop()
        k -= 1
        if k == 0:
            return node.val
        node = node.right

4Lowest Common Ancestor of a BST (LeetCode 235)

🟠 Medium. Return the lowest common ancestor of nodes p and q in a BST.

text
[6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8 → 6

Approach. Use the ordering: if both values are smaller than the node, the LCA is in the left subtree; if both are larger, in the right; otherwise the node splits them and is the LCA.

Complexity. O(h) time, O(1) space.

typescript
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}
function _tree(level: (number | null)[]): TreeNode | null {
  if (!level.length || level[0] === null) return null;
  const root = new TreeNode(level[0]); const q: TreeNode[] = [root]; let i = 1;
  while (q.length && i < level.length) {
    const node = q.shift()!;
    if (i < level.length && level[i] !== null) { node.left = new TreeNode(level[i]!); q.push(node.left); }
    i++;
    if (i < level.length && level[i] !== null) { node.right = new TreeNode(level[i]!); q.push(node.right); }
    i++;
  }
  return root;
}
function _level(root: TreeNode | null): (number | null)[] {
  const out: (number | null)[] = []; const q: (TreeNode | null)[] = [root];
  while (q.length) { const n = q.shift()!; if (n) { out.push(n.val); q.push(n.left, n.right); } else out.push(null); }
  while (out.length && out[out.length - 1] === null) out.pop();
  return out;
}

function lcaBst(root: TreeNode | null, p: number, q: number): number {
  let node = root;
  while (node) {
    if (p < node.val && q < node.val) node = node.left;
    else if (p > node.val && q > node.val) node = node.right;
    else return node.val;
  }
  return -1;
}
python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def _tree(level):
    if not level or level[0] is None:
        return None
    root = TreeNode(level[0]); q = [root]; i = 1
    while q and i < len(level):
        node = q.pop(0)
        if i < len(level) and level[i] is not None:
            node.left = TreeNode(level[i]); q.append(node.left)
        i += 1
        if i < len(level) and level[i] is not None:
            node.right = TreeNode(level[i]); q.append(node.right)
        i += 1
    return root

def _level(root):
    out, q = [], [root]
    while q:
        n = q.pop(0)
        if n:
            out.append(n.val); q.append(n.left); q.append(n.right)
        else:
            out.append(None)
    while out and out[-1] is None:
        out.pop()
    return out

def lca_bst(root, p, q):
    node = root
    while node:
        if p < node.val and q < node.val:
            node = node.left
        elif p > node.val and q > node.val:
            node = node.right
        else:
            return node.val

5Insert into a Binary Search Tree (LeetCode 701)

🟠 Medium. Insert val (not already present) into the BST and return the root.

text
[4,2,7,1,3], val = 5 → [4,2,7,1,3,5]

Approach. Walk down as in search until you fall off the tree; attach the new node there. The recursive version returns the (possibly new) subtree root.

Complexity. O(h) time.

typescript
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}
function _tree(level: (number | null)[]): TreeNode | null {
  if (!level.length || level[0] === null) return null;
  const root = new TreeNode(level[0]); const q: TreeNode[] = [root]; let i = 1;
  while (q.length && i < level.length) {
    const node = q.shift()!;
    if (i < level.length && level[i] !== null) { node.left = new TreeNode(level[i]!); q.push(node.left); }
    i++;
    if (i < level.length && level[i] !== null) { node.right = new TreeNode(level[i]!); q.push(node.right); }
    i++;
  }
  return root;
}
function _level(root: TreeNode | null): (number | null)[] {
  const out: (number | null)[] = []; const q: (TreeNode | null)[] = [root];
  while (q.length) { const n = q.shift()!; if (n) { out.push(n.val); q.push(n.left, n.right); } else out.push(null); }
  while (out.length && out[out.length - 1] === null) out.pop();
  return out;
}

function insertIntoBST(root: TreeNode | null, val: number): TreeNode {
  if (!root) return new TreeNode(val);
  if (val < root.val) root.left = insertIntoBST(root.left, val);
  else root.right = insertIntoBST(root.right, val);
  return root;
}
python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def _tree(level):
    if not level or level[0] is None:
        return None
    root = TreeNode(level[0]); q = [root]; i = 1
    while q and i < len(level):
        node = q.pop(0)
        if i < len(level) and level[i] is not None:
            node.left = TreeNode(level[i]); q.append(node.left)
        i += 1
        if i < len(level) and level[i] is not None:
            node.right = TreeNode(level[i]); q.append(node.right)
        i += 1
    return root

def _level(root):
    out, q = [], [root]
    while q:
        n = q.pop(0)
        if n:
            out.append(n.val); q.append(n.left); q.append(n.right)
        else:
            out.append(None)
    while out and out[-1] is None:
        out.pop()
    return out

def insert_into_bst(root, val):
    if not root:
        return TreeNode(val)
    if val < root.val:
        root.left = insert_into_bst(root.left, val)
    else:
        root.right = insert_into_bst(root.right, val)
    return root

6Convert Sorted Array to Binary Search Tree (LeetCode 108)

🟢 Easy. Build a height-balanced BST from a sorted array.

text
[-10,-3,0,5,9] → [0,-3,9,-10,null,5] (one valid answer)

Approach. The middle element becomes the root (so both halves have equal size); recursively build the left half and the right half. Several balanced answers are valid.

Complexity. O(n) time, O(log n) stack.

typescript
class TreeNode {
  val: number;
  left: TreeNode | null;
  right: TreeNode | null;
  constructor(val = 0, left: TreeNode | null = null, right: TreeNode | null = null) {
    this.val = val;
    this.left = left;
    this.right = right;
  }
}
function _tree(level: (number | null)[]): TreeNode | null {
  if (!level.length || level[0] === null) return null;
  const root = new TreeNode(level[0]); const q: TreeNode[] = [root]; let i = 1;
  while (q.length && i < level.length) {
    const node = q.shift()!;
    if (i < level.length && level[i] !== null) { node.left = new TreeNode(level[i]!); q.push(node.left); }
    i++;
    if (i < level.length && level[i] !== null) { node.right = new TreeNode(level[i]!); q.push(node.right); }
    i++;
  }
  return root;
}
function _level(root: TreeNode | null): (number | null)[] {
  const out: (number | null)[] = []; const q: (TreeNode | null)[] = [root];
  while (q.length) { const n = q.shift()!; if (n) { out.push(n.val); q.push(n.left, n.right); } else out.push(null); }
  while (out.length && out[out.length - 1] === null) out.pop();
  return out;
}

function sortedArrayToBST(nums: number[]): TreeNode | null {
  const build = (lo: number, hi: number): TreeNode | null => {
    if (lo > hi) return null;
    const mid = (lo + hi) >> 1;
    return new TreeNode(nums[mid], build(lo, mid - 1), build(mid + 1, hi));
  };
  return build(0, nums.length - 1);
}
python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def _tree(level):
    if not level or level[0] is None:
        return None
    root = TreeNode(level[0]); q = [root]; i = 1
    while q and i < len(level):
        node = q.pop(0)
        if i < len(level) and level[i] is not None:
            node.left = TreeNode(level[i]); q.append(node.left)
        i += 1
        if i < len(level) and level[i] is not None:
            node.right = TreeNode(level[i]); q.append(node.right)
        i += 1
    return root

def _level(root):
    out, q = [], [root]
    while q:
        n = q.pop(0)
        if n:
            out.append(n.val); q.append(n.left); q.append(n.right)
        else:
            out.append(None)
    while out and out[-1] is None:
        out.pop()
    return out

def sorted_array_to_bst(nums):
    def build(lo, hi):
        if lo > hi:
            return None
        mid = (lo + hi) // 2
        return TreeNode(nums[mid], build(lo, mid - 1), build(mid + 1, hi))
    return build(0, len(nums) - 1)

🧠 Key takeaways

  • BST invariant: left < node < right for every ancestor, so operations walk one path, O(h).
  • Validate with an inherited (low, high) range or a strictly increasing inorder.
  • Inorder = sorted order: k-th smallest, min difference, recover swapped nodes.
  • Balanced trees (AVL/red-black) keep h = O(log n); C# has SortedSet/SortedDictionary.

🛠️ Practice exercises

Each exercise is a file in this topic folder. Code exercises are self-checking: run them and make the checks pass.

#1
algo_binary_search_trees_exercise_1.py
#2
algo_binary_search_trees_exercise_2.py

✅ Check yourself

Answer the questions — feedback is instant.

1. [5,4,6,null,null,3,7]: why isn't this a valid BST?
Ancestor ranges matter.
2. Inserting 1, 2, 3, …, n into a plain BST gives height…
Degenerates into a list.
3. Deleting a node with two children replaces it with…
Keeps the ordering.
4. LCA in a BST can be found in…
Use the ordering.