Kth Smallest Element in a BST
MediumGiven the root of a binary search tree and an integer k, return the kth smallest value (1-indexed) among all the nodes in the tree. A binary search tree guarantees that for every node, all values in its left subtree are smaller and all values in its right subtree are larger, which provides the key property needed to solve this problem efficiently.
Examples
Example 1:
Input: root = [3,1,4,null,2], k = 1
Output: 1
Explanation: The BST has nodes 1, 2, 3, 4. An inorder traversal visits them in the order 1, 2, 3, 4 (ascending). The 1st smallest element is 1, which is the leftmost node in the tree.
Example 2:
Input: root = [5,3,6,2,4,null,null,1], k = 3
Output: 3
Explanation: The BST has nodes 1, 2, 3, 4, 5, 6. Inorder traversal visits them as 1, 2, 3, 4, 5, 6. The 3rd smallest element is 3, which is the root node. We only needed to traverse down to the 3rd visited node to find the answer.
Constraints:
1 <= k <= n <= 10^4
n is the total number of nodes in the tree
Algorithm Walkthrough
The critical property that makes this problem solvable in optimal time is that an inorder traversal of a BST visits nodes in strictly ascending order. This is not a coincidence — it is a direct consequence of the BST invariant: every left child is smaller than its parent, and every right child is larger. When an inorder traversal visits the left subtree first, then the node itself, then the right subtree, the natural ordering of the BST produces a sorted sequence. This means the 1st node visited during inorder traversal is the smallest, the 2nd is the second smallest, and so on. To find the kth smallest element, we simply perform an inorder traversal and count the nodes we visit. When the count reaches k, we return that node's value.
While a recursive inorder traversal works perfectly, the iterative approach using an explicit stack is often preferred because it allows early termination and uses bounded space. The idea is to simulate the recursive call stack manually. We start by pushing all left children onto the stack, going as far left as possible — this gives us the smallest element on top of the stack. We then pop the top node, count it as one visited node, and if the count equals k, we return its value immediately. If not, we move to that node's right subtree and repeat the process of going left. This guarantees we always process nodes in ascending order, just like recursive inorder traversal.
Let's trace through Example 1 with root = [3, 1, 4, null, 2] and k = 1. We start at node 3 and go left to node 1. Node 1 has no left child, so the stack is [3, 1] and we pop 1. We decrement k to 0 and return 1 immediately. We never even needed to visit node 2, 3, or 4. This early termination is what makes the iterative approach efficient — in the best case, when k = 1, we only traverse down the left spine of the tree.
Now let's trace Example 2 with root = [5, 3, 6, 2, 4, null, null, 1] and k = 3. Starting at node 5, we go left: 5 → 3 → 2 → 1. The stack is [5, 3, 2, 1]. We pop 1, k becomes 2 (not zero, continue). Node 1 has no right child, so we pop 2, k becomes 1 (still not zero). Node 2 has no right child, so we pop 3, k becomes 0 — we return 3. The answer is found without visiting nodes 4, 5, or 6.
An important advantage of the iterative approach is that it uses O(h) space, where h is the height of the tree, rather than O(n) space that a full inorder traversal collecting all elements would require. The stack only holds the path from the root to the current node, which is at most h elements. For a balanced BST, h = O(log n), making the space usage very efficient. For a completely skewed tree, h = O(n) in the worst case, but this is unavoidable since any traversal must at least track where it is in the tree.
An alternative worth knowing is the recursive inorder traversal with a counter. You define a helper that performs inorder traversal and increments a count each time a node is visited. When the count equals k, you record the node's value. However, the recursive version cannot easily terminate early — you'd need to propagate a "found" signal up through the recursion, which adds complexity. The iterative approach naturally supports early termination with a simple return statement.
For scenarios where findKthSmallest is called repeatedly on the same BST with different k values, it's worth considering augmenting the BST nodes with subtree size counts. Each node stores the number of nodes in its left subtree. Then, to find the kth smallest, you compare k with the left subtree size at each node — if k equals the left size + 1, the current node is the answer; if k is less, recurse left; if k is greater, recurse right with k adjusted. This approach gives O(h) time per query after O(n) preprocessing, which is optimal for repeated queries.
- Initialize an empty stack and a pointer
currto the root - While the stack is not empty or
curris not null, go as far left as possible, pushing nodes onto the stack - Pop the top node from the stack and decrement
k - If
k == 0, return the popped node's value immediately - Otherwise, set
currto the popped node's right child and repeat
Idea Map
Key insight: Inorder traversal of BST gives sorted ascending order
Go as far left as possible, pushing each node onto the stack
Pop top node, decrement k. If k == 0, return its value
If not found, move to the right child and repeat the go-left process
Complexity Analysis
Time Complexity
O(k) — In the best case, we only visit k nodes before finding the answer. In the worst case (e.g., k = n on a right-skewed tree), we visit up to O(n) nodes. Each node is pushed and popped from the stack exactly once, so the work per node is O(1). The tight upper bound is O(h + k), where h is the tree height (to reach the leftmost node initially) plus k nodes visited during the traversal.
Space Complexity
O(h) — The stack holds at most h nodes at any time, where h is the height of the tree. For a balanced BST, h = O(log n). In the worst case of a completely skewed tree, h = O(n). No additional data structures are used beyond the stack, making this the most space-efficient approach for a single query.
Code
def kthSmallest(root, k):
Defines the main function that takes the root of a BST and an integer k, returning the kth smallest value (1-indexed) in the tree using iterative inorder traversal.
stack = []
Initialize an empty stack to simulate the recursive call stack. The stack will hold the path of nodes from the root down to the current position, enabling us to backtrack after processing left subtrees.
curr = root
Pointer to track the current node being explored. We start at the root and will navigate left, right, and up using the stack.
while stack or curr:
Main loop: continue as long as there are nodes to process on the stack or unexplored nodes remaining. Both conditions are needed — `stack` handles backtracking, `curr` handles moving into new subtrees.
while curr:
Inner loop: traverse as far left as possible. In a BST, the leftmost node is the smallest, so we push all left-path nodes onto the stack to process them in ascending order.
stack.append(curr)
Push the current node onto the stack before going to its left child. This ensures we can return to this node after processing its entire left subtree.
curr = curr.left
Move to the left child. This continues until we reach the leftmost node (curr becomes None), at which point the stack's top element is the next smallest unvisited node.
curr = stack.pop()
Pop the top node — this is the next node in sorted order. Since all smaller nodes (left subtree) have already been processed, this is the correct next element in the inorder sequence.
k -= 1
Decrement the counter. We have visited one more node in sorted order. When k reaches 0, the current node is the kth smallest.
if k == 0:
Check if we have found the kth smallest element. This enables early termination — we stop as soon as the answer is found without traversing the rest of the tree.
return curr.val
Return the value of the kth smallest node. This is the final answer to the problem.
curr = curr.right
Move to the right child to continue the inorder traversal. The right subtree contains all values larger than the current node. If there is no right child, the loop continues by popping the next node from the stack.
public int kthSmallest(TreeNode root, int k) {
Public entry point that takes the root of a BST and integer k, returning the kth smallest value using iterative inorder traversal with an explicit stack.
Stack<TreeNode> stack = new Stack<>();
Initialize a stack to hold TreeNode references. This simulates the recursion call stack for inorder traversal, keeping track of the path back up the tree.
TreeNode curr = root;
Pointer to track the current node. Starts at the root and navigates left, right, and back through the stack.
while (curr != null || !stack.isEmpty()) {
Main loop continues while there are unvisited nodes. `curr != null` means there are new nodes to explore; `!stack.isEmpty()` means there are nodes to backtrack to.
while (curr != null) {
Inner loop: push all left children onto the stack to reach the leftmost (smallest) node. This is the first phase of inorder traversal.
stack.push(curr);
Push the current node onto the stack before descending to its left child, so we can return to process it after the left subtree is done.
curr = curr.left;
Move to the left child. Loop continues until curr is null, meaning we've reached the bottom-left of the current subtree.
curr = stack.pop();
Pop the top node — the next node in inorder (ascending) order. Its entire left subtree has already been processed.
if (--k == 0) return curr.val;
Pre-decrement k and check if it's zero. If so, the current node is the kth smallest — return its value immediately. The `--k` inline saves a line while decrementing before the comparison.
curr = curr.right;
Move to the right child. All remaining values in the right subtree are larger than the current node. If curr is null, the outer loop continues by popping from the stack.
}
End of the main while loop. In practice, the return inside the loop always executes since k is guaranteed to be valid (1 <= k <= n).
return -1;
Fallback return (never reached given valid input). Required by Java's compiler since the method must return an int on all paths.
}
End of the kthSmallest method.
class Solution {
Defines the Solution class for LeetCode. Contains a single public method that finds the kth smallest element using iterative inorder traversal.
public:
Public access specifier for the LeetCode-required entry point method.
int kthSmallest(TreeNode* root, int k) {
Entry point taking a BST root pointer and integer k. Returns the kth smallest value using iterative inorder traversal with an explicit stack.
stack<TreeNode*> st;
Initialize a stack of TreeNode pointers. This simulates the recursion stack for inorder traversal, storing the path back to parent nodes.
TreeNode* curr = root;
Pointer to the current node being explored, starting at the root.
while (curr || !st.empty()) {
Main loop: continue while there are nodes to explore (`curr`) or nodes on the stack to backtrack to (`!st.empty()`). Both conditions ensure complete traversal.
while (curr) {
Inner loop: go as far left as possible, pushing each node onto the stack. This reaches the leftmost (smallest) node in the current subtree.
st.push(curr);
Push the current node onto the stack before descending left. This allows us to return to this node after processing its left subtree.
curr = curr->left;
Move to the left child. The loop exits when curr is null, meaning we've reached the bottom-left of the current path.
curr = st.top(); st.pop();
Retrieve and remove the top node from the stack — this is the next node in sorted (ascending) order. Combined into one line since both operations always happen together.
if (--k == 0) return curr->val;
Pre-decrement k. If k reaches zero, the current node is the kth smallest — return its value immediately. This enables early termination without visiting the rest of the tree.
curr = curr->right;
Move to the right child to continue inorder traversal. The right subtree contains all values greater than the current node. If curr is null, the outer loop pops the next ancestor.
}
End of the main while loop. The return inside the loop always executes for valid k.
return -1;
Fallback return (unreachable with valid input). Required because the compiler must see a return statement on all code paths.
}
End of the kthSmallest method.
};
End of the Solution class.
Edge Cases & Common Mistakes
k is 1-indexed, not 0-indexed
A common mistake is treating k as 0-indexed and looking for the (k-1)th visited node, or conversely not accounting for the 1-indexing correctly. When k = 1, you should return the very first node visited (the leftmost node). If you decrement k before comparing (using `--k` or `k -= 1` before the check), make sure the comparison is `k == 0`. If you compare first and decrement after, compare with `k == 1`. Mixing these up will give an off-by-one error.
For repeated queries, consider augmenting the BST with subtree size counts
If the problem requires finding the kth smallest element multiple times on the same BST (or supports insertions/deletions between queries), augment each node with the size of its subtree. Then you can navigate directly to the kth element in O(h) time per query by comparing k with the left subtree size at each node — no traversal needed. This is a common optimization in order-statistic trees and is useful in follow-up questions.
Inorder traversal on BST naturally gives sorted order — exploit this property
This is the core insight of the problem. A general binary tree would require collecting all elements and sorting them (O(n log n)) or using a more complex selection algorithm. But a BST's structure guarantees that inorder traversal produces sorted output. Always exploit the BST property when present — it turns what would be an O(n log n) problem into O(k) or O(n), a significant improvement.
Related Problems
Understanding BST Properties and Inorder Traversal
Binary search trees are one of the most fundamental data structures in computer science. Understanding BST properties — including how inorder traversal produces sorted output, why the left subtree always contains smaller values, and how to exploit these properties for efficient search — is essential for technical interviews and real-world applications like database indexing and balanced tree implementations.
Learn more about understanding BST properties and inorder traversal →Disclaimer: This problem is for educational purposes. Practice the 'Kth Smallest Element in a BST' problem on LeetCode.