Find Kth Smallest Element
Problem and examples
Given an unsorted array of integers and a number k, your task is to find the kth smallest element in the array using an efficient technique.
kis 1-based, meaningk = 1refers to the smallest element,k = 2refers to the second smallest, and so on.- If
kis larger than the number of elements in the array, return-1or indicate that it is out of bounds.
This problem can be solved in linear average time using the Quickselect algorithm, which is related to Quicksort but optimized to find a specific order statistic without full sorting.
| Input Array | k | Output | Description |
|---|---|---|---|
| [7, 10, 4, 3, 20, 15] | 3 | 7 | The 3rd smallest element is 7Visualization |
| [7, 10, 4, 3, 20, 15] | 4 | 10 | The 4th smallest element is 10Visualization |
| [1] | 1 | 1 | Single element, return it directlyVisualization |
| [9, 8, 7, 6] | 1 | 6 | Smallest element is 6Visualization |
| [5, 3, 2, 4, 1] | 5 | 5 | Largest element (k = n)Visualization |
| [2, 1] | 3 | -1 | k exceeds array lengthVisualization |
| [] | 1 | -1 | Empty array, return error or -1Visualization |
Explore Find Kth Smallest Element using Quickselect
Load an example or enter your own input. Use the player controls to follow each change.
Understanding the Problem
We are given an unsorted array and a number k. Our goal is to find the kth smallest element in the array.
Let’s understand this with an example:
Input: arr = [7, 10, 4, 3, 20, 15], k = 3
Output: 7
If we sorted the array, it would become: [3, 4, 7, 10, 15, 20]. The 3rd smallest element is 7.
But sorting the entire array takes O(n log n) time. We want to find the answer more efficiently.
Approach: Quickselect Algorithm
The Quickselect algorithm helps us find the kth smallest element in average O(n) time — without sorting the whole array.
How Quickselect Works
We follow these steps:
- Choose a pivot element from the array (usually random).
- Partition the array into three parts:
lows: elements less than the pivotpivots: elements equal to the pivothighs: elements greater than the pivot
- Now compare
kwith the sizes of these parts:- If
k ≤ size of lows, then the answer lies in thelowspart. Recur on that. - If
k ≤ size of lows + size of pivots, the pivot itself is thekthsmallest element. - Else, the answer lies in the
highspart. Recur onhighswithk - size of lows - size of pivots.
- If
Let’s Visualize With the Same Example
arr = [7, 10, 4, 3, 20, 15], k = 3
- Choose pivot = 7
- Partition: lows = [4, 3], pivots = [7], highs = [10, 20, 15]
- lows has 2 elements, pivots has 1 → total = 3
- Since k = 3 is within (2 + 1), return pivot = 7
Handling Edge Cases
Case 1: Empty array
If the input array is empty, there's no element to find. Return -1.
Case 2: k is out of bounds
If k < 1 or k > length of array, return -1.
Case 3: Array has duplicates
The algorithm works even if duplicates exist because it separates values equal to the pivot.
Case 4: Array has one element
If the array has only one value and k = 1, then return that element directly.
Why This Is Efficient
Unlike full sorting, which looks at every element multiple times, Quickselect repeatedly focuses only on the part of the array where the answer could be. This smart narrowing saves time.
That’s how we solve the problem of finding the kth smallest element — step by step, clearly and efficiently!
- Given an array of numbers and an integer
k(1-indexed), the goal is to find the kth smallest element. - If the array contains only one element, return that element.
- Randomly choose a pivot from the array.
- Partition the array into three groups:
lows(elements less than the pivot),pivots(elements equal to the pivot), andhighs(elements greater than the pivot). - If
kis less than or equal to the size oflows, recursively search inlows. - If
kis within the size oflowspluspivots, the pivot is the kth smallest element. - Otherwise, recursively search in
highswith an updatedk(subtracting the sizes oflowsandpivots).
Implementation and efficiency
C implementation
#include <stdio.h>
#include <stdlib.h>
int main() {
int a = 10, b = 20;
int sum = a + b;
printf("Sum: %d\n", sum);
return 0;
}C++ implementation
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 20;
cout << "Sum: " << (a + b) << endl;
return 0;
}Python implementation
def add(a, b):
return a + b
if __name__ == '__main__':
a, b = 10, 20
print("Sum:", add(a, b))Java implementation
public class Main {
public static void main(String[] args) {
int a = 10, b = 20;
int sum = a + b;
System.out.println("Sum: " + sum);
}
}JavaScript implementation
function add(a, b) {
return a + b;
}
let a = 10, b = 20;
console.log("Sum:", add(a, b));Go implementation
package main
import "fmt"
func main() {
a, b := 10, 20
sum := a + b
fmt.Println("Sum:", sum)
}Rust implementation
fn main() {
let a = 10;
let b = 20;
let sum = a + b;
println!("Sum: {}", sum);
}Kotlin implementation
fun main() {
val a = 10
val b = 20
val sum = a + b
println("Sum: $sum")
}Swift implementation
import Foundation
let a = 10
let b = 20
let sum = a + b
print("Sum: \(sum)")TypeScript implementation
function add(a: number, b: number): number {
return a + b;
}
let a = 10, b = 20;
console.log("Sum:", add(a, b));Time complexity
| Case | Time | Explanation |
|---|---|---|
| best case | O(n) | If the pivot divides the array evenly, each recursive call reduces the problem size by half, leading to linear time complexity. |
| average case | O(n) | On average, the random pivot leads to a fairly balanced partition, resulting in linear time complexity for finding the kth element. |
| worst case | O(n²) | In the worst case (e.g., when the smallest or largest element is always chosen as pivot), the partitioning is highly unbalanced, resulting in quadratic time complexity. |
Space complexity
O(1) (in-place) or O(n) (with extra arrays)
If implemented in-place like Lomuto partition, it uses constant space. But if implemented with extra arrays for lows, pivots, and highs, it uses linear space.