algorithm
array
sorting
data structures
selection

How to find the kth largest element in an unsorted array of length n in On?

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

Finding the k-th largest element in an unsorted array is a common problem in computer science. A direct approach might be to sort the array and then directly pick the k-th element, but this costs O(nlogn)O(n \log n) time complexity. However, by employing more advanced techniques, such as the Quickselect algorithm, we can solve this problem in average O(n)O(n) time.

Quickselect Algorithm

Overview

Quickselect is an efficient selection algorithm developed by Tony Hoare, who is also known for creating Quicksort. It is essentially a partial sorting algorithm that focuses on finding the k-th smallest or largest element without fully sorting the data.

The core idea of Quickselect is similar to that of Quicksort:

  1. Choose a pivot: A pivot is chosen from the array.
  2. Partitioning: Reorder the array so that all elements lesser than the pivot come before it, and all elements greater come after it.
  3. Recursive Selection: Based on the position of the pivot, decide whether to recursively apply the algorithm to the left or right partition.

How it Works

To find the k-th largest element in an unsorted array, convert the problem to finding the (n-k)-th smallest element since it's more intuitive to reason about finding the smallest elements.

Consider an unsorted array arr of length n and an integer k:

python
1def quickselect(arr, left, right, k):
2    if left == right:  # If the list contains only one element
3        return arr[left]
4
5    pivot_index = partition(arr, left, right)
6
7    if k == pivot_index:
8        return arr[k]
9    elif k < pivot_index:
10        return quickselect(arr, left, pivot_index - 1, k)
11    else:
12        return quickselect(arr, pivot_index + 1, right, k)
13
14def partition(arr, left, right):
15    pivot = arr[right]
16    i = left
17    for j in range(left, right):
18        if arr[j] <= pivot:
19            arr[i], arr[j] = arr[j], arr[i]
20            i = i + 1
21    arr[i], arr[right] = arr[right], arr[i]
22    return i
23
24def find_kth_largest(arr, k):
25    return quickselect(arr, 0, len(arr) - 1, len(arr) - k)

Example

Consider the array arr = [3, 2, 1, 5, 6, 4] and we want to find the 2nd largest element.

  1. Initial Call: quickselect(arr, 0, 5, 4) (as 6 - 2 = 4)
  2. Partition Step: Assuming pivot selected is 4, reorder to [3, 2, 1, 4, 6, 5]. The pivot index is 3.
  3. Recursive Selection:
    • Because 4 (pivot index) < 5 (k), recurse into right subarray [6, 5].
  4. Partition Step: Select 5 as a pivot, reordering to [5, 6].
  5. Recursive Selection: 5 is now at the 4-th index. Return 5.

Hence, the 2nd largest number is 5.

Time Complexity

Quickselect, similar to Quicksort, has different time complexities based on the selection of pivot:

  • Best/Average Case: O(n)O(n). The algorithm works by partitioning the array, where ideally the pivot divides the array into roughly equal parts, leading to a logarithmic number of recursive calls.
  • Worst Case: O(n2)O(n^2). This occurs when the smallest or largest element is always chosen as the pivot, leading to skewed partitioning. Randomized pivot selection or using the median of three can help alleviate this issue.

Key Comparisons

Comparing Quickselect to other strategies such as sorting the entire array:

StrategyTime ComplexitySpace ComplexityNotes
Full SortO(nlogn)O(n \log n)O(1)O(1) in-place / O(n)O(n) externalGood for multiple selections
QuickselectAverage: O(n)O(n) / Worst: O(n2)O(n^2)O(1)O(1) if in-placeOptimal for single selection in average case

Additional Techniques

Randomized Quickselect

Randomly selecting a pivot helps avoid the O(n2)O(n^2) worst case in Quickselect. Randomization ensures the algorithm is effective statistically.

Heap Implementation

A min-heap or max-heap can be utilized to find the k-th largest element. Build a min-heap of size k, and iterate over the array, keeping the largest k elements in the heap. This achieves O(nlogk)O(n \log k) time complexity and is useful when k is small relative to n.

Conclusion

Finding the k-th largest element in an unsorted array efficiently is a solved problem in computer science. By leveraging Quickselect, you can achieve average linear time complexity. Understanding and implementing Quickselect correctly is crucial for optimizing search operations in large datasets.


Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms