Skip to content

Kth Smallest Element in a BST

Given the root of a binary search tree and an integer k, return the kth smallest value (1-indexed) of all the values of the nodes in the tree.

InputkOutputExplanation
Tree: 3, 1→null, 1→2, 411Sorted: [1, 2, 3, 4], 1st = 1
Tree: 3, 1→null, 1→2, 432Sorted: [1, 2, 3, 4], 3rd = 2
Tree: 5, 3, 613Sorted: [3, 5, 6], 1st = 3
  • The number of nodes in the tree is n.
  • 1 <= k <= n <= 10^4
  • 0 <= Node.val <= 10^4
ApproachTimeSpaceKey IdeaBest When
In-Order DFSO(n)O(h)Recursive in-order, count k nodes, returnGeneral case — simple and elegant
Morris In-OrderO(n)O(1)Thread-based traversal, no recursion stackSpace-critical — embedded systems, interview edge case
  • Pick In-Order DFS as your primary solution.
  • Learn Morris In-Order if you want to optimize space to O(1).
Most Common
In-Order DFS
O(n) time · O(h) space
Space-Optimized
Morris In-Order
O(n) time · O(1) space
★ Recommended

Recursively traverse the tree in in-order (left → node → right). Maintain a counter that increments with each node visited. When the counter equals k, return the current node’s value.

⏱ Time O(n) Worst case: visit all nodes 💾 Space O(h)

Input: Tree with values [3, 1, 4, 2], k = 1

In-order sequence: [1, 2, 3, 4]

StepNodecountAction
111count == k, return 1 ✓

Animated walkthrough

How in-order DFS finds the kth smallest element

Watch the count increment as nodes are visited in sorted order. Stop when count reaches k.

Step 1 of 2 Target: 1
Waiting to begin...
Array state
Memory / lookup state

function kthSmallest_inorder(root, k):
count = 0
result = null
function inorder(node):
if node is null or result is not null:
return
inorder(node.left)
count++
if count == k:
result = node.val
return
inorder(node.right)
inorder(root)
return result
kth_smallest_element_in_bst_inorder.py
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def kth_smallest_inorder_dfs(root: Optional[TreeNode], k: int) -> int:
"""
In-order DFS approach to find kth smallest element in BST.
In-order traversal of BST yields sorted sequence.
Count nodes as we traverse, return when we reach the kth node.
Time: O(k) in best case, O(n) in worst case
Space: O(h) - recursion stack, h = height
"""
count = [0]
result = [None]
def inorder(node):
if not node or result[0] is not None:
return
# Traverse left subtree
inorder(node.left)
# Process current node
count[0] += 1
if count[0] == k:
result[0] = node.val
return
# Traverse right subtree
inorder(node.right)
inorder(root)
return result[0]
# Test cases
if __name__ == "__main__":
# Example 1: Find 1st smallest
root1 = TreeNode(3)
root1.left = TreeNode(1)
root1.right = TreeNode(4)
root1.left.right = TreeNode(2)
print(kth_smallest_inorder_dfs(root1, 1)) # 1
# Example 2: Find 3rd smallest
print(kth_smallest_inorder_dfs(root1, 3)) # 2
advanced

Morris traversal enables in-order traversal without recursion or an explicit stack. It uses “threading” — temporary pointers to connect nodes. This achieves O(1) space.

The algorithm works in two passes per node: on the first visit, create a thread back to the current node; on the second visit, remove the thread and process the node.

⏱ Time O(n) All nodes visited 💾 Space O(1) No extra structure

Input: Tree with values [3, 1, 4, 2], k = 1

  1. Start at 3 (root).
  2. Find predecessor of 3: it’s 2.
  3. Thread 2 → 3 (first visit to 2).
  4. Move to left child 1.
  5. 1 has no left child. Visit 1, count = 1. Return 1.
function kthSmallest_morris(root, k):
count = 0
current = root
while current is not null:
if current.left is null:
// No left child: visit current node
count++
if count == k:
return current.val
current = current.right
else:
// Find in-order predecessor
predecessor = current.left
while predecessor.right and predecessor.right != current:
predecessor = predecessor.right
if predecessor.right is null:
// First visit: create thread
predecessor.right = current
current = current.left
else:
// Second visit: remove thread, process current
predecessor.right = null
count++
if count == k:
return current.val
current = current.right
return -1
kth_smallest_element_in_bst_morris.py
from typing import Optional
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def kth_smallest_morris_inorder(root: Optional[TreeNode], k: int) -> int:
"""
Morris In-Order traversal to find kth smallest element in BST.
Uses tree threading to traverse without recursion or extra stack space.
Space-efficient: O(1) extra space (modifying and restoring tree structure).
Time: O(n) - visit each node twice
Space: O(1) - no extra data structures
"""
count = 0
current = root
while current:
if current.left is None:
# Left is None, process current node
count += 1
if count == k:
return current.val
current = current.right
else:
# Find in-order predecessor
predecessor = current.left
while predecessor.right and predecessor.right != current:
predecessor = predecessor.right
if predecessor.right is None:
# Create link to current node
predecessor.right = current
current = current.left
else:
# Link exists, remove it and process current
predecessor.right = None
count += 1
if count == k:
return current.val
current = current.right
return -1
# Test cases
if __name__ == "__main__":
# Example 1: Find 1st smallest
root1 = TreeNode(3)
root1.left = TreeNode(1)
root1.right = TreeNode(4)
root1.left.right = TreeNode(2)
print(kth_smallest_morris_inorder(root1, 1)) # 1
# Example 2: Find 3rd smallest
print(kth_smallest_morris_inorder(root1, 3)) # 2