Kth Largest Element in an Array
Problem statement
Given an unsorted array of integers nums and an integer k, return the k-th largest value in the array. This is the value that would sit at position k if the array were sorted from largest to smallest, so duplicates count separately: in [4, 4, 1], both the first and second largest are 4.
k is always between 1 and the length of the array. Try to do better than sorting the whole array.
Examples
Example 1
Input: nums = [7, 2, 9, 4, 4, 1], k = 2
Output: 7
Explanation: From largest to smallest the values are 9, 7, 4, 4, 2, 1. The second is 7.
Example 2
Input: nums = [3, 8, 8, 5, 1], k = 4
Output: 3
Explanation: Largest to smallest: 8, 8, 5, 3, 1. The two 8s count as separate positions, so the fourth is 3.
Hints
Approach
Use quickselect: quicksort's partition, but only follow the side that contains the answer.
- The
k-th largest is the element at indexn - kin ascending order. Call thattarget. - Pick a random pivot and partition the current range into three blocks: less than, equal to, and greater than the pivot.
- If
targetfalls in the equal block, the pivot is the answer. If it falls in the smaller block, continue only there; otherwise continue only in the larger block.
Each round discards, on average, a constant fraction of the range, so the total work is n + n/2 + n/4 + ..., which is linear on average. The random pivot makes the O(n^2) worst case very unlikely, and the three-way partition keeps arrays full of duplicates fast.
O(n) average, O(n^2) worst caseSpace O(n) for the working copy (O(1) if you may modify the input)import random class Solution: def findKthLargest(self, nums: list[int], k: int) -> int: target = len(nums) - k # index of the answer in ascending order lo, hi = 0, len(nums) - 1 nums = list(nums) while True: pivot = nums[random.randint(lo, hi)] # three-way partition of nums[lo..hi]: < pivot | == pivot | > pivot lt, i, gt = lo, lo, hi while i <= gt: if nums[i] < pivot: nums[lt], nums[i] = nums[i], nums[lt] lt += 1 i += 1 elif nums[i] > pivot: nums[i], nums[gt] = nums[gt], nums[i] gt -= 1 else: i += 1 if target < lt: hi = lt - 1 # answer is among the smaller values elif target > gt: lo = gt + 1 # answer is among the larger values else: return pivot # target falls in the block equal to pivotFollow-up questions
- The numbers arrive as a stream too large to store. Which approach still works?
- Return the
klargest values themselves, not just thek-th.
Frequently asked questions
State sorting first, then the heap, since it is reliable and easy to code. Offer quickselect as the average-linear option, and mention its worst case. Many interviewers are happy with the heap and ask for quickselect only as a follow-up.
With a two-way partition, an array where many values equal the pivot can split very unevenly, which pushes quickselect toward its quadratic worst case. Grouping all pivot-equal values together lets one round skip past all of them at once.
Percentiles are the same question: the p99 latency of 10,000 requests is roughly the 100th largest value. Quickselect finds it without sorting everything, and the size-k heap does it over a live stream of request timings.