Given the root of a binary search tree (BST) and an integer k, find the kth smallest node value.

Example:

Given the BST below and k = 5:

Image represents a binary tree data structure.  The tree is rooted at node 5, which connects to two child nodes: node 2 on the left and node 7 on the right. Node 2 further branches into two leaf nodes: node 1 on the left and node 4 on the right. Similarly, node 7 branches into two leaf nodes: node 6 on the left and node 9 on the right.  Each node is represented by a circle containing a numerical value (1 through 9).  The connections between nodes are represented by lines, indicating a parent-child relationship within the tree structure.  No URLs or parameters are present in the image; the only information conveyed is the numerical labels and their hierarchical arrangement within the binary tree.
Output: 6

Constraints:

In Plain English

New to this one? Start here. Below is the core idea in everyday language, plus a real-world analogy—then the sections that follow build on it with the formal reasoning, code, and step-by-step walkthroughs.

🏆 A real-world picture: a leaderboard

A BST already stores its values in sorted order — you just have to read them out the right way. Reading them smallest-first is like scanning a leaderboard from the bottom rank up; the kth name you reach is your answer, and you can stop the moment you get there.

Intuition - Recursive

A naive approach to this problem is to traverse the tree and store all the nodes in an array, sort the array, and return the kth element. This approach, however, does not take advantage of the fact that we're dealing with a BST.

Consider again the BST from the example:

Image represents a binary tree data structure.  The tree is rooted at node 5, which connects to two child nodes: node 2 on the left and node 7 on the right. Node 2 further branches into two leaf nodes: node 1 on the left and node 4 on the right. Similarly, node 7 branches into two leaf nodes: node 6 on the left and node 9 on the right.  Each node is represented by a circle containing a numerical value (1 through 9).  The connections between nodes are represented by lines, indicating a parent-child relationship within the tree structure.  No URLs or parameters are present in the image; the only information conveyed is the numerical labels and their hierarchical arrangement within the binary tree.

We know that in a BST, each node’s value is larger than all the nodes to its left and smaller than all the nodes to its right. This structure means that BSTs inherently possess a sorted order. Given this, it should be possible to construct a sorted array of the tree's values by traversing the tree, without the need for additional sorting.

We now need a method to traverse the binary tree that allows us to encounter the nodes in their sorted order.

What are our options? We can immediately rule out any traversal algorithms that process the root node first, such as breadth-first search and preorder traversal, since the root node is not guaranteed to have the smallest value in a BST. This also indicates that we need an algorithm that starts with the leftmost node since this is always the smallest node in a BST. Additionally, the algorithm should end at the rightmost node since this would be the largest node.

This leads us to an ideal traversal algorithm: inorder traversal, where for each node, the left subtree is processed first, followed by the current node, and then the right subtree.

Image represents a binary search tree structure illustrating an inorder traversal.  A central node labeled 'X' is depicted, connected by lines to two triangular shapes representing subtrees.  A left-pointing arrow on the line connecting 'X' to the left subtree indicates values less than 'X' are contained within the light-blue, left subtree labeled 'left subtree' and the text 'less than x'.  Similarly, a right-pointing arrow on the line connecting 'X' to the right subtree indicates values greater than 'X' are contained within the purple, right subtree labeled 'right subtree' and the text 'greater than x'. To the right, the text 'inorder traversal:' describes the traversal order as 'left subtree → x → right subtree', indicating that in an inorder traversal, the left subtree is visited first, followed by the root node 'X', and finally the right subtree.

To build the sorted list of values using inorder traversal, we can design a recursive function. When called on the root node, it returns a sorted list of all the values in the BST.

When the function is called for any node during the recursive process, it constructs a sorted list of the values in the subtree rooting from that node. This is achieved by first obtaining the sorted values from its left subtree, then adding the current node's value, and finally appending the sorted values from its right subtree. This process is carried out through recursive calls to the left and right children.

Once we have the full list of sorted values, we can simply return the value at the (k - 1)th index to get the kth smallest value.

Implementation - Recursive

from ds import TreeNode
    
def kth_smallest_number_in_BST_recursive(root: TreeNode, k: int) -> int:
    sorted_list = inorder(root)
    return sorted_list[k - 1]
    
# Inorder traversal function to attain a sorted list of nodes from the BST.
def inorder(node: TreeNode) -> List[int]:
    if not node:
        return []
    return inorder(node.left) + [node.val] + inorder(node.right)
void inorder(TreeNode* n, vector<int>& v) {
    if (n == nullptr) {
        return;
    }
    inorder(n->left, v);
    v.push_back(n->val);
    inorder(n->right, v);
}
int kthSmallestNumberInBSTRecursive(TreeNode* root, int k) {
    vector<int> v;
    inorder(root, v);
    return v[k - 1];                            // 1-indexed
}
void inorder(TreeNode n, List<Integer> v) {
    if (n == null) return;
    inorder(n.left, v);
    v.add(n.val);
    inorder(n.right, v);
}
int kthSmallestNumberInBSTRecursive(TreeNode root, int k) {
    List<Integer> v = new ArrayList<>(); inorder(root, v);
    return v.get(k - 1);
}

Complexity Analysis

Time complexity: The time complexity of kth_smallest_number_in_BST_recursive is O(n)O(n), where nn denotes the number of nodes in the tree. This is because we need to traverse through all nn nodes of the tree to attain the sorted list.

Space complexity: The space complexity is O(n)O(n) due to the space taken up by sorted_list, as well as the recursive call stack, which can grow as large as the height of the binary tree. The largest possible height of a binary tree is nn.

Intuition - Iterative

Since we only need the kth smallest value, storing all n values in a list might not be necessary. Ideally, we’d like to find a way to traverse through k nodes instead of n. How can we modify our approach to achieve this?

If we had a way to stop inorder traversal once we've reached the kth node in the traversal, we would land on our answer. An iterative approach would allow for this since we’d be able to exit traversal once we’ve reached the kth node — something that’s quite difficult to achieve using recursion.

We know inorder traversal is a DFS algorithm and that DFS algorithms can be implemented iteratively using a stack. Let’s explore this idea further.


Consider what happened during recursive inorder traversal in the previous approach:

Let’s replicate the above steps iteratively using a stack.

  1. Move as far left as possible, adding each node to the stack as we move left.
  1. Once we can no longer move left, we pop the node off the top of the stack. Let's call it the current node. Initially, this node will represent the smallest node. After this, the current node will subsequently represent the next smallest node, and so on until we reach the kth smallest node.

  2. Move to the current node’s right child.

Implementation - Iterative

def kth_smallest_number_in_BST_iterative(root: TreeNode, k: int) -> int:
    stack = []
    node = root
    while stack or node:
        # Move to the leftmost node and add nodes to the stack as we go so they
        # can be processed in future iterations.
        while node:
            stack.append(node)
            node = node.left
        # Pop the top node from the stack to process it, and decrement 'k'.
        node = stack.pop()
        k -= 1
        # If we have processed 'k' nodes, return the value of the 'k'th smallest
        # node.
        if k == 0:
            return node.val
        # Move to the right subtree.
        node = node.right
int kthSmallestNumberInBSTIterative(TreeNode* root, int k) {
    stack<TreeNode*> st;
    TreeNode* node = root;
    while (!st.empty() || node != nullptr) {
        while (node != nullptr) {
            st.push(node);
            node = node->left;
        }
        node = st.top();
        st.pop();
        k--;                                   // one more node visited in sorted order
        if (k == 0) {
            return node->val;
        }
        node = node->right;
    }
    return -1;
}
int kthSmallestNumberInBSTIterative(TreeNode root, int k) {
    Deque<TreeNode> st = new ArrayDeque<>();
    TreeNode node = root;
    while (!st.isEmpty() || node != null) {
        while (node != null) { st.push(node); node = node.left; }
        node = st.pop();
        if (--k == 0) return node.val;
        node = node.right;
    }
    return -1;
}

Complexity Analysis

Time complexity: The time complexity of kth_smallest_number_in_BST_iterative is O(k+h)O(k+h), where hh denotes the height of the tree. Here’s why:

Space complexity: The space complexity is O(h)O(h) since the stack can store up to O(h)O(h) during the traversal to the leftmost node. In the worst case, the height of the tree is nn, resulting in a space complexity of O(n)O(n).

Dry Runs

Two step-by-step walkthroughs of the algorithm below: a valid case (the expected happy path) and an invalid / edge case that exercises the tricky parts. Each step shows the program state as the code runs—the same steps apply to Python, C++ and Java.

✅ Dry run 1 (k = 3, early stop) — answer 4
stepstack (top → right)popk after
dive left5, 3, 23
pop 2, no right5, 322
pop 3, dive right → push 45, 431
pop 4 → k = 0540 → return 4

We returned after visiting only 2, 3, 4 — nodes 5, 8, 9 were never touched. answer = 4

❗ Dry run 2 (k = 6 = n, full traversal) — answer 9

Asking for the largest means counting down through every value. Inorder order: 2, 3, 4, 5, 8, 9.

visited (in order)k after each
25
34
43
52
81
90 → return 9

Here early-stop buys nothing — every node is visited. This is the O(n) worst case, and it also confirms k = n returns the maximum. answer = 9

The same steps in each language

A plain list as the stack; append/pop from the end. Decrement k on each visit and return when it reaches 0.

std::stack of node pointers; --k == 0 both decrements and tests in one step, matching Python’s k -= 1 then check.

ArrayDeque used as a stack (push/pop). The --k == 0 check is identical to C++. Same left-spine dive.