Kth Smallest Element in BST

Ethan Davis
Data Structures and Algorithms DSA
2 min readJun 25, 2024
Data Structures and Algorithms

Statement

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

Constraints

  • number of nodes = n
  • 1 ≤ kn ≤ 500
  • 0 ≤ node.data ≤ 10⁴

Solution

"""
production algorithm
"""


class Solution:
def kth_smallest_element(self, root, k):
"""
time complexity O(n)
space complexity O(n)
"""
count, result = [k], []
self.kth_smallest_element_helper(root, count, result)
return result[0]

def kth_smallest_element_helper(self, root, count, result):
"""
time complexity O(n)
space complexity O(n)
"""
if result:
return
if root is None:
return
self.kth_smallest_element_helper(root.left, count, result)
count[0] -= 1
if count[0] == 0:
result.append(root.data)
self.kth_smallest_element_helper(root.right, count, result)
"""
unit tests
"""

from unittest import TestCase
from algorithms.dfs.kth_smallest_element_in_bst.solution import Solution
from data_structures.binary_tree.binary_tree import BinaryTreeNode


class SolutionTestCase(TestCase):
def test_0th_smallest_element(self):
# Given
root = BinaryTreeNode(9)
root.left = BinaryTreeNode(3)
root.right = BinaryTreeNode(11)
root.left.left = BinaryTreeNode(-1)
root.left.right = BinaryTreeNode(6)
root.right.left = BinaryTreeNode(10)
root.right.right = BinaryTreeNode(16)
root.right.right.right = BinaryTreeNode(18)
k = 1
solution = Solution()

# When
actual = solution.kth_smallest_element(root, k)

# Then
expected = -1
self.assertEqual(actual, expected)

def test_kth_smallest_element(self):
# Given
root = BinaryTreeNode(9)
root.left = BinaryTreeNode(3)
root.right = BinaryTreeNode(11)
root.left.left = BinaryTreeNode(-1)
root.left.right = BinaryTreeNode(6)
root.right.left = BinaryTreeNode(10)
root.right.right = BinaryTreeNode(16)
root.right.right.right = BinaryTreeNode(18)
k = 5
solution = Solution()

# When
actual = solution.kth_smallest_element(root, k)

# Then
expected = 10
self.assertEqual(actual, expected)

def test_nth_smallest_element(self):
# Given
root = BinaryTreeNode(9)
root.left = BinaryTreeNode(3)
root.right = BinaryTreeNode(11)
root.left.left = BinaryTreeNode(-1)
root.left.right = BinaryTreeNode(6)
root.right.left = BinaryTreeNode(10)
root.right.right = BinaryTreeNode(16)
root.right.right.right = BinaryTreeNode(18)
k = 8
solution = Solution()

# When
actual = solution.kth_smallest_element(root, k)

# Then
expected = 18
self.assertEqual(actual, expected)

Strategy

Depth First Search.

Explanation

The algorithm does an inorder traversal of the binary search tree. It counts the number of nodes seen so far, so that when it finds the kth element, it saves that element. When the kth smallest element has been found, the algorithm backs out of recursion, and then returns the result.

Time Complexity

At most, the algorithm walks every node of the binary search tree. Let n be the number of nodes in the binary search tree. Then, the time complexity of the algorithm is O(n).

Space Complexity

At most, the algorithm walks every node in the binary search tree, and the binary search tree is a degenerate tree. The depth of recursion would reach n, where n is the number of nodes in the binary search tree. Therefore, the auxiliary space complexity of the algorithm is O(n).

Links

--

--