Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Depth-First Search (DFS)

Builds on BST Bounds and Tree Traversals, which you haven’t finished yet.

P1MediumBuilt on Tree Traversals~4 min speedrun

Inorder Traversal as a Sorted Stream (Kth Smallest in BST, BST Iterator)

Built on
Tree TraversalsAn inorder walk visits a BST in ascending order, so it can stop as soon as it has the value it needs.
The problem

Kth Smallest Element in a BST (LC 230)(opens leetcode.com)

You get the root of a binary search tree and a whole number k. Imagine writing every value in the tree in a row, smallest first, and numbering the positions from 1: return the value that lands in position k.

In a binary search tree, the values in a node's left subtree are smaller than the node's value, and the values in its right subtree are larger.

Follow-up: if nodes are inserted and deleted often and this question is asked again and again, how would you make each answer faster?

Example 1
Input:root = [3,1,4,null,2], k = 1
Output:1
Written smallest first, the values are 1, 2, 3, 4. Position 1 holds 1, a leaf on the left, even though 3 sits at the top of the tree.
1234

BST Inorder

BST ➔ inorder walk (left, node, right) ➔ values in sorted order
Spot it when: The tree is a BST and the answer depends on the values in sorted order: the k-th smallest, the gap between neighbouring values, the values nearest a target, or stepping through the values one at a time like an iterator.
BST Inorder
Python
1from typing import Optional
2 
3class TreeNode:
4 def __init__(self, val: int = 0, left: Optional["TreeNode"] = None, right: Optional["TreeNode"] = None):
5 self.val = val
6 self.left = left
7 self.right = right
8 
9def kth_smallest(root: Optional[TreeNode], k: int) -> int:
10 """Kth Smallest Element in a BST: an inorder walk visits the values in sorted order.
11 Time: O(H + k) | Space: O(H) stack
12 """
13 # Nodes whose left subtree is being walked; each waits for its visit
14 stack: list[TreeNode] = []
15 node = root
16 while node or stack:
17 while node: # 1. Dive left: every smaller value sits in a left subtree
18 stack.append(node)
19 node = node.left
20 node = stack.pop() # 2. Visit: the smallest value not visited yet
21 k -= 1 # Count a node when it is visited, never when it is pushed
22 if k == 0:
23 return node.val # The k-th visit is the k-th smallest value
24 node = node.right # 3. Its right subtree holds the next larger values
25 return -1 # Never reached: 1 <= k <= n
Invariant: Values leave stack in ascending order: when stack.pop() returns node, every value smaller than node.val has already been visited, and every node still on stack holds a larger value.

An inorder walk of a BST (left subtree, then the node, then the right subtree) visits the values in sorted order, so read the tree as a sorted list, one value per visit: count, compare or collect at the moment stack.pop() hands you a node, and stop as soon as you have the answer. The inner loop pushes node and moves to node.left until it falls off the tree, so when a node is popped, its left subtree has been visited, and so has every ancestor it sits to the right of: those are exactly the smaller values. node = node.right then moves on to the next larger values. The trap is where you count: k -= 1 belongs right after stack.pop(), not next to stack.append(node), because nodes are pushed from the root down, and on [3,1,4,null,2] counting pushes returns 3 for k = 1 instead of 1.

See it run

Inorder walk that stops at the k-th visit, step by step

k 3 · node 5 · answer not found yet

k 3 · node 3 · answer not found yet

k 3 · node 2 · answer not found yet

k 3 · node 1 · answer not found yet

k 3 · node 1 · answer not found yet

k 2 · node 1 · answer not found yet

k 1 · node 2 · answer not found yet

k 0 · node 3 · answer 3

Each circle is a tree node. The stack row has its top on the right. The visited row shows the values in the order they were popped.

  • node the node the loop is looking at
  • on stack pushed, and waiting for its left subtree to finish
  • visited popped and counted
  • answer the k-th value popped

Start at the root 5 with k = 3. Dive left and push every node on the stack.

Push 5. Move to its left child 3. The count k stays 3.

Push 3. Move to its left child 2. The count k stays 3.

Push 2. Move to its left child 1. The count k stays 3.

Push 1. It has no left child, so the dive stops. The count k stays 3.

Pop 1 and count it: k is now 2. It has no right child.

Pop 2 and count it: k is now 1. It has no right child.

Pop 3 and count it: k is now 0. This is visit number 3, so 3 is the answer for k = 3.

12345node6
stack
empty
visited in order
empty
1 / 8
Gotchas1 of 4

Gotcha 1 of 4

  1. 1
    The trap

    Gotcha 1: Counting k -= 1 when a node is pushed

    Mistake
    while node:
        stack.append(node)
        k -= 1
        if k == 0:
            return node.val
        node = node.left
    node = stack.pop()
    Fix
    while node:
        stack.append(node)
        node = node.left
    node = stack.pop()
    k -= 1
    if k == 0:
        return node.val

    What happens: A pushed node is only waiting for its visit. The pushes go from the root down, so the root is pushed first. The values come in sorted order only when nodes are popped. In the example, counting pushes stops at the root 3 for k = 1. The smallest value is 1.

    Example: Kth Smallest Element in a BST (LC 230): root = [3,1,4,null,2], k = 1
    Mistake: returns 3Fix: returns 1
  2. 2

    Gotcha 2: Looping while stack instead of while node or stack

    Mistake
    while stack:
    Fix
    while node or stack:

    What happens: The stack starts empty, and node starts at the root. With while stack, the loop body never runs, and the function returns -1. The stack also empties after the root is visited, while node still points at the root's right subtree.

    Example: root = [3,1,4,null,2], k = 1
    Mistake: returns -1Fix: returns 1
  3. 3

    Gotcha 3: Pushing node.right straight onto stack

    Mistake
    if node.right:
        stack.append(node.right)
    node = None
    Fix
    node = node.right

    What happens: The right child's own left subtree holds smaller values than the right child. node = node.right lets the inner loop dive left from it first. Pushing node.right onto stack skips the dive into its left subtree. On [2,1,4,null,null,3], the walk visits 1, 2 and 4. It never visits 3, because 3 is the left child of 4.

    Example: root = [2,1,4,null,null,3], k = 3
    Mistake: returns 4Fix: returns 3
  4. 4

    Gotcha 4: Walking every node when the nearest values are already found

    What happens: Closest Binary Search Tree Value II (LC 272) asks for the k values nearest to a target. Keep a window of the last k visited values. Once it is full, drop its first value when a new value is closer to the target. Stop the walk when a new value is not closer. Every later value is larger, so it is farther still.

Not this one if…
  • You only need the one place where a value belongs, as in Insert into a Binary Search Tree (LC 701), not the values in order: a single path down from the root decides it. See BST Bounds
  • The values arrive one at a time and are not kept in a BST, as in Kth Largest Element in a Stream (LC 703): there is no tree whose inorder walk hands you sorted order. See Top-K Heap

Deep Dive

Why values leave the stack in ascending order

In a BST (binary search tree), a node's left subtree holds smaller values and its right subtree holds larger values. An inorder walk visits the left subtree, then the node, then the right subtree. So a node is visited after all of its smaller values, and before all of its larger values.

The blueprint does this with a stack. The inner loop pushes node and moves to node.left until there is no node. The top of stack is then the smallest value that is not visited yet. stack.pop() visits it. Then node = node.right moves to the next larger values. Every node that stays on stack has not been visited yet, and each one holds a larger value than the node just popped.

Example: in Kth Smallest Element in a BST (LC 230), take root = [5, 3, 6, 2, 4, null, null, 1] and k = 3. The pushes are 5, 3, 2 and 1. The pops are 1, then 2, then 3. After the third pop, k is 0, so the answer is 3. The values came out in the order 1, 2, 3.

The trap: count when a node is popped, not when it is pushed

A node is pushed from the root down, so the first node pushed is the root. The root is not the smallest value. A pushed node is only waiting for its visit. The pop is the visit.

If k -= 1 sits next to stack.append(node), the count follows the pushes. On root = [3, 1, 4, null, 2] with k = 1, the first push is the root 3. The count reaches 0 there, so the function returns 3. The correct answer is 1.

Two more traps are in the loop. The outer condition must be while node or stack. At the start, stack is empty, so while stack never runs and the function returns -1. Also use node = node.right after the pop. If you push node.right onto stack instead, the dive into the left side of that right child is skipped. On [2, 1, 4, null, null, 3] with k = 3, that version returns 4. The correct answer is 3, because 3 is the left child of 4.

Stopping early, and the cost O(H + k)

The walk stops at the k-th visit. It does not read the whole tree. Before the first pop it pushes one node per level on the way to the leftmost node, so that is H pushes, where H is the height of the tree. After that, each pop and each right move is one more visit.

Example: the tree [4, 2, 6, 1, 3, 5, 7] has 7 nodes and height 3. With k = 1 the walk makes 3 pushes and 1 pop. With k = 7 it makes 7 pushes and 7 pops.

Compare this with building a list of all N values and then reading position k - 1. That always costs O(N) time. The stack holds at most H nodes, so the space is O(H). For a chain of 100 nodes that leans to the left, the walk makes 100 pushes before the first pop. That is the worst case for H.

Which problems read the sorted stream, and the neighbour cards

Once the walk gives the values in order, other questions are short. In Minimum Absolute Difference in BST (LC 530) and Minimum Distance Between BST Nodes (LC 783), the smallest gap is always between two values that are next to each other in sorted order. Keep the previous value and compare it with each new value.

In Closest Binary Search Tree Value II (LC 272), keep the last k visited values. When a new value is not closer to the target than the oldest kept value, stop. Every later value is larger and therefore farther.

BST Bounds is the neighbour card. In Insert into a Binary Search Tree (LC 701), one path from the root decides the answer, so you do not need the values in order. In Kth Largest Element in a Stream (LC 703), the values arrive one at a time and are not stored in a tree. There is no tree to walk in order.

60-Second Pitch

"In a BST, an inorder walk visits the values in ascending order. So the k-th visit is the k-th smallest value. I walk with an explicit stack. The inner loop pushes the node and moves left until it falls off the tree. Then I pop, which gives the smallest value not yet visited. I count there, and I return when k reaches 0. Then I move to the right child. I count at the pop and not at the push, because the push goes from the root down and the root is not the smallest. The time is O(H + k), because the first dive pushes H nodes and then each visit is cheap. The space is O(H) for the stack."

Common Questions

Why does an inorder walk of a BST give sorted values?

The BST rule puts smaller values in the left subtree and larger values in the right subtree. Inorder visits left, then the node, then right. So a node comes after all smaller values and before all larger values. By induction, the whole walk is in ascending order.

What is the time complexity of the Kth Smallest Element in a BST (LC 230) walk?

O(H + k). The first dive pushes about H nodes, where H is the height of the tree. Then each of the k visits does a small amount of work. The space is O(H) for the stack. A walk that first collects all values costs O(N).

The tree changes often and you must answer many k-th smallest queries. What would you change?

The walk costs O(H + k) for every query. To make it faster, store in each node the number of nodes in its left subtree. Then you can go left or right by comparing k with that count, and one query takes O(H). The count must be updated on every insert and every delete.

How do you do the same with recursion?

Write inorder(node): call it on node.left, then count node, then call it on node.right. Stop when the count reaches k. It has the same O(H + k) time. The call stack takes the place of stack, so a very deep tree can exceed the recursion limit.

How do you find the smallest gap between two values in a BST?

The smallest gap is between two values that are next to each other in sorted order. Walk the tree in order, keep the previous value, and update the best gap with node.val - prev at each visit. This is Minimum Absolute Difference in BST (LC 530). It takes O(N) time and O(H) space.

SWE Reasoning

Spot it

  • The tree is a BST, and the question depends on the order or the rank of the values: k-th smallest, a gap between neighbours, the nearest values to a target.
  • The wording says "in sorted order", "next smaller", "next larger" or asks for an iterator over the values.
  • You can stop at some point, so a full pass over the tree is not needed.
  • A value must be compared only with the value visited just before it.
  • The call tree would be deep, so an explicit stack is safer than recursion.

The invariant, step by step

  1. The inner loop pushes node and moves to node.left until there is no node. The top of stack is then the smallest value that is not visited yet.
  2. node = stack.pop() visits the top. All values smaller than node.val have been visited. All nodes still on stack hold larger values.
  3. k -= 1 counts this visit. When k reaches 0, this is the k-th visit, so node.val is the k-th smallest.
  4. node = node.right moves to the right subtree. Its values are larger than node.val and smaller than the next node on stack.
  5. The loop runs while node or stack has something left, so no value is skipped.
  6. Each node is pushed once and popped once. The walk visits the values in ascending order, one value per pop.

Traps

  • Counting at the push. The root is pushed first and is not the smallest value. Count right after stack.pop().
  • while stack as the outer loop. The stack is empty at the start, so the loop never runs. Use while node or stack.
  • Pushing node.right onto the stack. The left side of the right child is skipped. Set node = node.right and let the inner loop dive.
  • Reading the whole tree for a small k. Return as soon as k reaches 0.
  • Using it on a tree that is not a BST. The inorder order is sorted only for a BST.

Practice

Canonical LeetCode:Kth Smallest Element in a BST (LC 230)Minimum Absolute Difference in BST (LC 530)Minimum Distance Between BST Nodes (LC 783)Closest Binary Search Tree Value II (LC 272)Increasing Order Search Tree (LC 897)
Theory Context•Depth-First Search (DFS)

Builds on BST Bounds and Tree Traversals, which you haven’t finished yet.

P1MediumBuilt on Tree Traversals~4 min speedrun

Inorder Traversal as a Sorted Stream (Kth Smallest in BST, BST Iterator)

Built on
Tree TraversalsAn inorder walk visits a BST in ascending order, so it can stop as soon as it has the value it needs.
The problem

Kth Smallest Element in a BST (LC 230)(opens leetcode.com)

You get the root of a binary search tree and a whole number k. Imagine writing every value in the tree in a row, smallest first, and numbering the positions from 1: return the value that lands in position k.

In a binary search tree, the values in a node's left subtree are smaller than the node's value, and the values in its right subtree are larger.

Follow-up: if nodes are inserted and deleted often and this question is asked again and again, how would you make each answer faster?

Example 1
Input:root = [3,1,4,null,2], k = 1
Output:1
Written smallest first, the values are 1, 2, 3, 4. Position 1 holds 1, a leaf on the left, even though 3 sits at the top of the tree.
1234

BST Inorder

BST ➔ inorder walk (left, node, right) ➔ values in sorted order
Spot it when: The tree is a BST and the answer depends on the values in sorted order: the k-th smallest, the gap between neighbouring values, the values nearest a target, or stepping through the values one at a time like an iterator.
BST Inorder
Python
1from typing import Optional
2 
3class TreeNode:
4 def __init__(self, val: int = 0, left: Optional["TreeNode"] = None, right: Optional["TreeNode"] = None):
5 self.val = val
6 self.left = left
7 self.right = right
8 
9def kth_smallest(root: Optional[TreeNode], k: int) -> int:
10 """Kth Smallest Element in a BST: an inorder walk visits the values in sorted order.
11 Time: O(H + k) | Space: O(H) stack
12 """
13 # Nodes whose left subtree is being walked; each waits for its visit
14 stack: list[TreeNode] = []
15 node = root
16 while node or stack:
17 while node: # 1. Dive left: every smaller value sits in a left subtree
18 stack.append(node)
19 node = node.left
20 node = stack.pop() # 2. Visit: the smallest value not visited yet
21 k -= 1 # Count a node when it is visited, never when it is pushed
22 if k == 0:
23 return node.val # The k-th visit is the k-th smallest value
24 node = node.right # 3. Its right subtree holds the next larger values
25 return -1 # Never reached: 1 <= k <= n
Invariant: Values leave stack in ascending order: when stack.pop() returns node, every value smaller than node.val has already been visited, and every node still on stack holds a larger value.

An inorder walk of a BST (left subtree, then the node, then the right subtree) visits the values in sorted order, so read the tree as a sorted list, one value per visit: count, compare or collect at the moment stack.pop() hands you a node, and stop as soon as you have the answer. The inner loop pushes node and moves to node.left until it falls off the tree, so when a node is popped, its left subtree has been visited, and so has every ancestor it sits to the right of: those are exactly the smaller values. node = node.right then moves on to the next larger values. The trap is where you count: k -= 1 belongs right after stack.pop(), not next to stack.append(node), because nodes are pushed from the root down, and on [3,1,4,null,2] counting pushes returns 3 for k = 1 instead of 1.

See it run

Inorder walk that stops at the k-th visit, step by step

k 3 · node 5 · answer not found yet

k 3 · node 3 · answer not found yet

k 3 · node 2 · answer not found yet

k 3 · node 1 · answer not found yet

k 3 · node 1 · answer not found yet

k 2 · node 1 · answer not found yet

k 1 · node 2 · answer not found yet

k 0 · node 3 · answer 3

Each circle is a tree node. The stack row has its top on the right. The visited row shows the values in the order they were popped.

  • node the node the loop is looking at
  • on stack pushed, and waiting for its left subtree to finish
  • visited popped and counted
  • answer the k-th value popped

Start at the root 5 with k = 3. Dive left and push every node on the stack.

Push 5. Move to its left child 3. The count k stays 3.

Push 3. Move to its left child 2. The count k stays 3.

Push 2. Move to its left child 1. The count k stays 3.

Push 1. It has no left child, so the dive stops. The count k stays 3.

Pop 1 and count it: k is now 2. It has no right child.

Pop 2 and count it: k is now 1. It has no right child.

Pop 3 and count it: k is now 0. This is visit number 3, so 3 is the answer for k = 3.

12345node6
stack
empty
visited in order
empty
1 / 8
Gotchas1 of 4

Gotcha 1 of 4

  1. 1
    The trap

    Gotcha 1: Counting k -= 1 when a node is pushed

    Mistake
    while node:
        stack.append(node)
        k -= 1
        if k == 0:
            return node.val
        node = node.left
    node = stack.pop()
    Fix
    while node:
        stack.append(node)
        node = node.left
    node = stack.pop()
    k -= 1
    if k == 0:
        return node.val

    What happens: A pushed node is only waiting for its visit. The pushes go from the root down, so the root is pushed first. The values come in sorted order only when nodes are popped. In the example, counting pushes stops at the root 3 for k = 1. The smallest value is 1.

    Example: Kth Smallest Element in a BST (LC 230): root = [3,1,4,null,2], k = 1
    Mistake: returns 3Fix: returns 1
  2. 2

    Gotcha 2: Looping while stack instead of while node or stack

    Mistake
    while stack:
    Fix
    while node or stack:

    What happens: The stack starts empty, and node starts at the root. With while stack, the loop body never runs, and the function returns -1. The stack also empties after the root is visited, while node still points at the root's right subtree.

    Example: root = [3,1,4,null,2], k = 1
    Mistake: returns -1Fix: returns 1
  3. 3

    Gotcha 3: Pushing node.right straight onto stack

    Mistake
    if node.right:
        stack.append(node.right)
    node = None
    Fix
    node = node.right

    What happens: The right child's own left subtree holds smaller values than the right child. node = node.right lets the inner loop dive left from it first. Pushing node.right onto stack skips the dive into its left subtree. On [2,1,4,null,null,3], the walk visits 1, 2 and 4. It never visits 3, because 3 is the left child of 4.

    Example: root = [2,1,4,null,null,3], k = 3
    Mistake: returns 4Fix: returns 3
  4. 4

    Gotcha 4: Walking every node when the nearest values are already found

    What happens: Closest Binary Search Tree Value II (LC 272) asks for the k values nearest to a target. Keep a window of the last k visited values. Once it is full, drop its first value when a new value is closer to the target. Stop the walk when a new value is not closer. Every later value is larger, so it is farther still.

Not this one if…
  • You only need the one place where a value belongs, as in Insert into a Binary Search Tree (LC 701), not the values in order: a single path down from the root decides it. See BST Bounds
  • The values arrive one at a time and are not kept in a BST, as in Kth Largest Element in a Stream (LC 703): there is no tree whose inorder walk hands you sorted order. See Top-K Heap

Deep Dive

Why values leave the stack in ascending order

In a BST (binary search tree), a node's left subtree holds smaller values and its right subtree holds larger values. An inorder walk visits the left subtree, then the node, then the right subtree. So a node is visited after all of its smaller values, and before all of its larger values.

The blueprint does this with a stack. The inner loop pushes node and moves to node.left until there is no node. The top of stack is then the smallest value that is not visited yet. stack.pop() visits it. Then node = node.right moves to the next larger values. Every node that stays on stack has not been visited yet, and each one holds a larger value than the node just popped.

Example: in Kth Smallest Element in a BST (LC 230), take root = [5, 3, 6, 2, 4, null, null, 1] and k = 3. The pushes are 5, 3, 2 and 1. The pops are 1, then 2, then 3. After the third pop, k is 0, so the answer is 3. The values came out in the order 1, 2, 3.

The trap: count when a node is popped, not when it is pushed

A node is pushed from the root down, so the first node pushed is the root. The root is not the smallest value. A pushed node is only waiting for its visit. The pop is the visit.

If k -= 1 sits next to stack.append(node), the count follows the pushes. On root = [3, 1, 4, null, 2] with k = 1, the first push is the root 3. The count reaches 0 there, so the function returns 3. The correct answer is 1.

Two more traps are in the loop. The outer condition must be while node or stack. At the start, stack is empty, so while stack never runs and the function returns -1. Also use node = node.right after the pop. If you push node.right onto stack instead, the dive into the left side of that right child is skipped. On [2, 1, 4, null, null, 3] with k = 3, that version returns 4. The correct answer is 3, because 3 is the left child of 4.

Stopping early, and the cost O(H + k)

The walk stops at the k-th visit. It does not read the whole tree. Before the first pop it pushes one node per level on the way to the leftmost node, so that is H pushes, where H is the height of the tree. After that, each pop and each right move is one more visit.

Example: the tree [4, 2, 6, 1, 3, 5, 7] has 7 nodes and height 3. With k = 1 the walk makes 3 pushes and 1 pop. With k = 7 it makes 7 pushes and 7 pops.

Compare this with building a list of all N values and then reading position k - 1. That always costs O(N) time. The stack holds at most H nodes, so the space is O(H). For a chain of 100 nodes that leans to the left, the walk makes 100 pushes before the first pop. That is the worst case for H.

Which problems read the sorted stream, and the neighbour cards

Once the walk gives the values in order, other questions are short. In Minimum Absolute Difference in BST (LC 530) and Minimum Distance Between BST Nodes (LC 783), the smallest gap is always between two values that are next to each other in sorted order. Keep the previous value and compare it with each new value.

In Closest Binary Search Tree Value II (LC 272), keep the last k visited values. When a new value is not closer to the target than the oldest kept value, stop. Every later value is larger and therefore farther.

BST Bounds is the neighbour card. In Insert into a Binary Search Tree (LC 701), one path from the root decides the answer, so you do not need the values in order. In Kth Largest Element in a Stream (LC 703), the values arrive one at a time and are not stored in a tree. There is no tree to walk in order.

60-Second Pitch

"In a BST, an inorder walk visits the values in ascending order. So the k-th visit is the k-th smallest value. I walk with an explicit stack. The inner loop pushes the node and moves left until it falls off the tree. Then I pop, which gives the smallest value not yet visited. I count there, and I return when k reaches 0. Then I move to the right child. I count at the pop and not at the push, because the push goes from the root down and the root is not the smallest. The time is O(H + k), because the first dive pushes H nodes and then each visit is cheap. The space is O(H) for the stack."

Common Questions

Why does an inorder walk of a BST give sorted values?

The BST rule puts smaller values in the left subtree and larger values in the right subtree. Inorder visits left, then the node, then right. So a node comes after all smaller values and before all larger values. By induction, the whole walk is in ascending order.

What is the time complexity of the Kth Smallest Element in a BST (LC 230) walk?

O(H + k). The first dive pushes about H nodes, where H is the height of the tree. Then each of the k visits does a small amount of work. The space is O(H) for the stack. A walk that first collects all values costs O(N).

The tree changes often and you must answer many k-th smallest queries. What would you change?

The walk costs O(H + k) for every query. To make it faster, store in each node the number of nodes in its left subtree. Then you can go left or right by comparing k with that count, and one query takes O(H). The count must be updated on every insert and every delete.

How do you do the same with recursion?

Write inorder(node): call it on node.left, then count node, then call it on node.right. Stop when the count reaches k. It has the same O(H + k) time. The call stack takes the place of stack, so a very deep tree can exceed the recursion limit.

How do you find the smallest gap between two values in a BST?

The smallest gap is between two values that are next to each other in sorted order. Walk the tree in order, keep the previous value, and update the best gap with node.val - prev at each visit. This is Minimum Absolute Difference in BST (LC 530). It takes O(N) time and O(H) space.

SWE Reasoning

Spot it

  • The tree is a BST, and the question depends on the order or the rank of the values: k-th smallest, a gap between neighbours, the nearest values to a target.
  • The wording says "in sorted order", "next smaller", "next larger" or asks for an iterator over the values.
  • You can stop at some point, so a full pass over the tree is not needed.
  • A value must be compared only with the value visited just before it.
  • The call tree would be deep, so an explicit stack is safer than recursion.

The invariant, step by step

  1. The inner loop pushes node and moves to node.left until there is no node. The top of stack is then the smallest value that is not visited yet.
  2. node = stack.pop() visits the top. All values smaller than node.val have been visited. All nodes still on stack hold larger values.
  3. k -= 1 counts this visit. When k reaches 0, this is the k-th visit, so node.val is the k-th smallest.
  4. node = node.right moves to the right subtree. Its values are larger than node.val and smaller than the next node on stack.
  5. The loop runs while node or stack has something left, so no value is skipped.
  6. Each node is pushed once and popped once. The walk visits the values in ascending order, one value per pop.

Traps

  • Counting at the push. The root is pushed first and is not the smallest value. Count right after stack.pop().
  • while stack as the outer loop. The stack is empty at the start, so the loop never runs. Use while node or stack.
  • Pushing node.right onto the stack. The left side of the right child is skipped. Set node = node.right and let the inner loop dive.
  • Reading the whole tree for a small k. Return as soon as k reaches 0.
  • Using it on a tree that is not a BST. The inorder order is sorted only for a BST.

Practice

Canonical LeetCode:Kth Smallest Element in a BST (LC 230)Minimum Absolute Difference in BST (LC 530)Minimum Distance Between BST Nodes (LC 783)Closest Binary Search Tree Value II (LC 272)Increasing Order Search Tree (LC 897)
© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•