Kth Largest Element in an Array
You get an array of integers nums and an integer k. Return the k-th largest value in nums: the value at position k, counting from 1, once the array is sorted from largest to smallest.
Equal values count separately. In [5, 5, 1] the largest value is 5 and the second largest is also 5.
Function
- numsinteger-array
- the values to rank
- kinteger
- which largest value to return, 1 for the largest
- Returnsinteger
- the k-th largest value, counting duplicates
Constraints
1 ≤ k ≤ nums.length ≤ 104-104 ≤ nums[i] ≤ 104- Equal values count as separate values.
Examples
- Input
- nums = [7, 2, 9, 4, 9, 1]k = 2
- Output
- 9
- Explanation
- From largest to smallest the values are
9, 9, 7, 4, 2, 1. The two 9s count separately, so the second largest is9, not7.
- Input
- nums = [5, -3, 8, 0, 2]k = 4
- Output
- 0
- Explanation
- From largest to smallest the values are
8, 5, 2, 0, -3, and the fourth of them is0.
- Input
- nums = [6]k = 1
- Output
- 6
- Explanation
- With one value and
k = 1, that value is the largest.
+15 hidden tests on Submit
Follow-up
Values now arrive one at a time. Can you report the median of all values seen so far after each arrival, in O(log n) time per value?
Hints
Open them one at a time. Each one gives away a little more.
Sorted from largest to smallest, the answer sits at a known position. Which one? And do you need every other value in order to know it?
The k-th largest value is the smallest of the
klargest values. If you keep only theklargest values seen so far, which of them do you compare a new value against?Keep a min-heap of at most
kvalues. A new value replaces the top when it is larger, and the top at the end is the answer. ForO(n)average time, partition around a random pivot as quicksort does and keep only the side that holds indexn-k.
Solution
Sorting and reading one position answers the question, and it is fast enough here. What an interviewer wants to see is how much of that ordering you can skip, because you need one position, not all n. A min-heap of size k keeps only the values that can still be the answer, and quickselect partitions like quicksort but follows only the side that holds the answer, which brings the average time down to O(n).
Sort and read one position
Intuition
The k-th largest value is defined by the sorted order, so produce that order. Sorted from largest to smallest, [7, 2, 9, 4, 9, 1] becomes [9, 9, 7, 4, 2, 1], and the k-th largest sits at index k-1. For k = 2 that is index 1, the second 9. If your sort puts the smallest first, read index n-k instead: index 4 of [1, 2, 4, 7, 9, 9] is the same 9.
Duplicates need no special handling: a sort keeps every copy, and every copy takes its own position.
With n = 10^4 a sort makes about n log n ≈ 1.3 × 10^5 comparisons, which passes every test. The waste is that it puts all n values in order when only one position matters. The next two approaches do less of that work.
Algorithm
- Copy
numsso the caller's array stays as it was. - Sort the copy. Use a numeric comparison; some languages compare numbers as text by default.
- Return index
k-1of a largest-first order, or indexn-kof a smallest-first order.
def findKthLargest(nums, k):
# Largest first: the k-th largest sits at index k-1.
ordered = sorted(nums, reverse=True)
return ordered[k - 1]Keep the k largest in a min-heap
Intuition
The k-th largest value is the smallest of the k largest values. So walk through nums once and keep only the k largest values seen so far, in a min-heap. The top of a min-heap is its smallest value, which is exactly the candidate answer.
When a value x arrives and the heap holds fewer than k values, add it. Otherwise compare x with the top. If x is not larger, at least k values you kept are as large as x, so x can never be the answer and you skip it. If x is larger, the top has dropped out of the k largest: replace it with x. In example 2 with k = 4, the first four values fill the heap with 5, -3, 8, 0 and the top is -3. Then 2 beats -3 and replaces it, the top becomes 0, and 0 is the answer.
Every value costs at most one heap operation of O(log k), so the total is O(n log k) time and O(k) memory. That beats sorting when k is small, and it works on a stream: you never need all the values at once. Python has heapq, Java PriorityQueue, C++ priority_queue with greater, Go container/heap, Rust BinaryHeap with Reverse and PHP SplMinHeap. The code for the other languages writes the heap in an array, where the children of index i sit at 2i+1 and 2i+2, or at 2i and 2i+1 in Lua and R, which count from 1.
Algorithm
- Start with an empty min-heap.
- For each value
x, add it while the heap holds fewer thankvalues. - Once it holds
k, replace the top withxonly whenxis larger than the top. - After the last value, return the top of the heap.
import heapq
def findKthLargest(nums, k):
# A min-heap of the k largest values so far; its top is the smallest of them.
heap = []
for x in nums:
if len(heap) < k:
heapq.heappush(heap, x)
elif x > heap[0]:
heapq.heapreplace(heap, x) # drop the top, add x
return heap[0]Quickselect with a three-way partition
Intuition
Quicksort picks a pivot and partitions: smaller values to its left, larger values to its right. After one partition the pivot sits at its final sorted index, even though neither side is sorted yet. Quickselect uses that fact. In smallest-first order the answer lives at index target = n-k. After a partition, target is either left of the pivot, at the pivot, or right of it, so you continue on one side and drop the other.
For [7, 2, 9, 4, 9, 1] and k = 2, target is 6-2 = 4. Partition around 4: 2 and 1 take indexes 0 and 1, 4 takes index 2, and 7, 9, 9 take indexes 3 to 5. Index 4 is to the right, so you keep only indexes 3 to 5. Partition those around 9: 7 takes index 3 and both 9s take indexes 4 and 5. Index 4 holds a 9, so the answer is 9.
Use a three-way partition: values below the pivot, then values equal to it, then values above it, tracked by lt and gt. The equal block [lt, gt] is in its sorted place, so if target falls inside it you are done. With a plain two-way partition, an array of 10^4 copies of 7 shrinks by one value per round, about 5 × 10^7 steps; the three-way version answers it in one pass.
Pick the pivot at random. Half the time it lands in the middle half of the range, which cuts the range to at most three quarters, so the expected work is a few passes over n values: O(n). The worst case is still O(n²) if every pivot is an extreme value, and a fixed choice such as the first element hits it on sorted input. The code works on a copy, which costs O(n) memory; partitioning nums itself brings that to O(1) if you may change the input.
Algorithm
- Copy
numsintoa, settarget = n-k,lo = 0andhi = n-1. - Pick a random pivot from
a[lo..hi]. - Partition
a[lo..hi]into values below, equal to and above the pivot, leaving the equal values ina[lt..gt]. - If
target < lt, sethi = lt-1; iftarget > gt, setlo = gt+1; otherwise return the pivot. - Repeat from step 2.
import random
def findKthLargest(nums, k):
a = list(nums)
target = len(a) - k # the answer's index once a is sorted smallest first
lo, hi = 0, len(a) - 1
while True:
pivot = a[random.randint(lo, hi)]
# Three-way partition of a[lo..hi]: < pivot, then == pivot, then > pivot.
lt, i, gt = lo, lo, hi
while i <= gt:
if a[i] < pivot:
a[lt], a[i] = a[i], a[lt]
lt += 1
i += 1
elif a[i] > pivot:
a[i], a[gt] = a[gt], a[i]
gt -= 1
else:
i += 1
# Now a[lt..gt] all equal pivot, and they are in their sorted places.
if target < lt:
hi = lt - 1
elif target > gt:
lo = gt + 1
else:
return pivot
Pitfalls and edge cases
Most wrong answers come from duplicates and from mixing up the two ways to count positions.
- Removing duplicates first. The problem counts every copy: in
[7, 2, 9, 4, 9, 1]withk = 2the answer is9, but after turning the array into a set it becomes7. - Reading the wrong index.
kcounts from 1, so the answer is at indexk-1of a largest-first order and at indexn-kof a smallest-first order, notn-k-1. - Sorting numbers as text. In JavaScript and TypeScript,
[10, 9, 2].sort()gives[10, 2, 9]. Pass(a, b) => a - b. - Using a max-heap of size
k. Evicting the largest keeps theksmallest values and returns the k-th smallest. - Quickselect with a two-way partition or a fixed pivot. Many equal values or a sorted array then cost
O(n²), which the large tests include.
Frequently asked questions4
What is the time complexity of Kth Largest Element in an Array?
Sorting takes O(n log n) time. A min-heap of size k takes O(n log k) time and O(k) memory. Quickselect with a random pivot takes O(n) time on average and O(n²) in the worst case, which a random pivot makes very unlikely.
Why use a min-heap, not a max-heap, to find the kth largest element?
The heap stores the k largest values seen so far, and the one you must compare against and evict is the smallest of them. A min-heap keeps that value on top. A max-heap works only if you put all n values in it and pop k-1 times, which needs O(n) memory.
Should I use a heap or quickselect for the kth largest element?
Quickselect is faster on average, O(n), but it needs all values in memory and reorders them. The heap is O(n log k) with no bad worst case, and it works when values arrive one at a time and you cannot store them all. In an interview, explain both and code the one the follow-up asks for.
Can the kth largest element be found in linear time in the worst case?
Yes. The median-of-medians rule picks a pivot that is guaranteed to cut off a fixed share of the values, which makes selection O(n) in the worst case, though it is slower in practice than a random pivot. With values limited to -10^4 through 10^4 you can also count how often each value occurs and walk down from 10^4 until you have passed k values, in O(n + 2 × 10^4) time.
Similar problems
Problems that use the same ideas. Solving two or three of them is what makes a pattern stick.
Python
def findKthLargest(nums, k):
# Write code hereCase 1
Case 2
Case 3
Input
nums = [7, 2, 9, 4, 9, 1] k = 2
Expected
9