Kth Largest Element in an Array
Quickselect with Lomuto partition
Sorting costs O(n log n) just to learn one order statistic. Quickselect partitions around a pivot like quicksort — but then recurses into ONLY the side that contains the answer. The kth largest is simply the element that ends up at ascending index n−k once partitions place pivots on their true sorted positions.
Details
Animated on: Find the 3rd largest element of [7,2,9,4,5,1,8] without fully sorting it.
Problem:Kth Largest Element in an ArrayMedium
Pattern:Heap and Top K
Quickselect with Lomuto partition
step 1 / 15
k = 3 means the answer occupies ascending index n − k = 7 − 3 = 4. Goal: keep partitioning until some pivot lands EXACTLY on index 4.
- lo=0· arr[0] = 7
- hi=6· arr[6] = 8
1FUNCTION quickselect(arr, lo, hi, k):2 pivot = arr[hi]; set boundary i to lo - 13 FOR j from lo to hi-1:4 IF arr[j] <= pivot:5 move i one step right, then swap arr[i] with arr[j]6 swap arr[i+1] with arr[hi] (pivot to its final spot)7 p = i + 18 IF p equals k: RETURN arr[p]9 IF p < k: quickselect on the right side (p+1, hi, k)10 ELSE: quickselect on the left side (lo, p-1, k)
← / → step · space play · Home restart
Every step in words
Show all 15 steps
- k = 3 means the answer occupies ascending index n − k = 7 − 3 = 4. Goal: keep partitioning until some pivot lands EXACTLY on index 4.
- Partition pass 1: Lomuto picks the last cell as pivot — 8 — and sweeps j left to right growing a '≤ 8' prefix; i marks the prefix's right edge (starts before the array).
- j=0: 7 ≤ 8 → advance i to 0 and swap(0,0) — a free self-swap since 7 already sits in the ≤8 zone.
- j=1: 2 ≤ 8 → i climbs to 1, another trivial self-swap. The green prefix now holds {7, 2}.
- j=2: 9 > 8 → skip. Boundary i freezes at 1, so 9 waits on the big side — the NEXT small value will swap it rightward.
- j=3: 4 ≤ 8 → swap(i+1=2, j=3): 4 trades places with 9, exiling 9 rightward. Green prefix grows to {7, 2, 4}.
- j=4: 5 ≤ 8 → swap(3, 4) pushes the wandering 9 one slot further right. Prefix = {7, 2, 4, 5}.
- j=5: 1 ≤ 8 → swap(4, 5); the 9 lands at index 5, directly beside its pivot. Sweep done — everything left of index 5 is ≤ 8.
- Final move: swap(i+1=5, hi=6) drops the pivot 8 between its two camps — five values ≤ 8 on the left, only 9 on the right. Index 5 is now 8's FINAL sorted position.
- But we want index 4, and the pivot landed at p = 5 > 4 → recurse LEFT into indices 0..4. Bonus knowledge for free: index 5 holding 8 proves 8 IS the 2nd largest.
- Partition pass 2 over [7,2,4,5,1]: new pivot is the window's last cell, value 1 — the smallest here, so expect it to land at the window's far LEFT.
- All four comparisons fail (7, 2, 4, 5 all exceed 1), so i never advances past -1. Final swap(0, 4) trades 1 with 7 → pivot 1 lands at p = 0. Since 0 < 4, recurse RIGHT into indices 1..4.
- Partition pass 3 over window [2,4,5,7]: pivot = arr[4] = 7 — the largest of this slice, so it should land at the window's RIGHT end… which happens to be exactly our target index 4.
- Every element (2, 4, 5) is ≤ 7, so the sweep just walks through and the closing swap seats 7 at p = 4. p == k == 4 → return arr[4] = 7. Jackpot on the first try of this window.
- Answer: the 3rd largest is 7. Three pivots (8, 1, 7) each locked onto their true sorted position while whole regions were discarded untouched — average O(n) work total.
Now solve it yourself
Watching is the first half. The second is writing it without the animation.