Kth Largest Element in an Array
Find the kth largest value without sorting everything, by keeping only the k best candidates in a heap
Problem Statement
Given an integer array nums and an integer k, return the kth largest element.
Note this is the kth largest in sorted order, not the kth distinct value.
Input: nums = [3, 2, 1, 5, 6, 4], k = 2
Output: 5
Why: sorted descending → [6, 5, 4, 3, 2, 1], the 2nd is 5
Input: nums = [3, 2, 3, 1, 2, 4, 5, 5, 6], k = 4
Output: 4
Why: duplicates count — sorted descending → [6, 5, 5, 4, ...], the 4th is 4Intuition
The obvious solution is one line: sort descending, take index k - 1. That is O(n log n) and it is genuinely fine for most inputs.
But look at what it wastes. If n = 1,000,000 and k = 5, sorting carefully arranges all million values — and then you read five of them. The order of the other 999,995 was never needed.
The key insight
You do not need to know the order of everything. You only need to know which k values are the biggest, and among those, which is the smallest.
So carry a container that holds only the best k seen so far. Everything else can be thrown away the moment it arrives.
Why a min-heap, when we want the largest?
This is the part that feels backwards, so it is worth slowing down.
Your container holds the current top k. When a new number arrives, you must answer one question: does this newcomer deserve a place?
It deserves a place if it beats the weakest member of your current top k. And the weakest member of the top k is the smallest of them.
So the value you need instant access to is the minimum — which is exactly what a min-heap gives you.
Put another way
A min-heap of size k is a bouncer for a club with k places. The person standing nearest the door is the weakest one inside. When someone new turns up, you only compare against that one person.
And when the club is full and correct, the person at the door is the kth largest.
The real-world version
Imagine judging a competition and you only care about the top 3. You do not rank all 500 entries. You keep three slots on your desk. Each new entry is compared against the worst of the three you are holding. If it beats it, it takes its place and the loser is thrown out.
At the end, the worst of your three is the 3rd best overall.
Approach
Create an empty min-heap
It will never be allowed to hold more than k items.
Push each number
Walk nums once. Push every value in, without thinking.
If the heap now holds more than k, pop
The pop removes the smallest item, which is by definition the one least likely to belong in the top k.
The heap is back to size k.
The root is the answer
After the whole array is processed, the heap holds exactly the k largest values, and its root is the smallest of them — the kth largest overall.
Watch it run
Solution
import heapq
def find_kth_largest(nums: list[int], k: int) -> int:
"""Return the kth largest value using a min-heap of size k."""
heap: list[int] = []
for num in nums:
heapq.heappush(heap, num)
# Keep only the k best. The popped value is the current weakest.
if len(heap) > k:
heapq.heappop(heap)
# The root of a min-heap holding the top k is the kth largest.
return heap[0]
def find_kth_largest_shortest(nums: list[int], k: int) -> int:
"""The one-liner, for when clarity matters more than the constant factor."""
return heapq.nlargest(k, nums)[-1]Complexity Analysis
Time Complexity
O(n log k)
Space Complexity
O(k)
- Time — one pass over
nvalues, and each push or pop costsO(log k)because the heap never exceedskitems. Whenkis small this is very close toO(n). - Space — the heap holds at most
kvalues, no matter how largenis. This is the real prize: it lets you handle a stream of numbers too large to hold in memory.
Compared with sorting
| Approach | Time | Space | Best when |
|---|---|---|---|
| Sort, then index | O(n log n) | O(n) or O(log n) | k is close to n, or the code must be obvious |
Min-heap of size k | O(n log k) | O(k) | k is much smaller than n, or the input is a stream |
| Quickselect | O(n) average | O(1) | You need the theoretical best and can accept O(n²) worst case |
Do not assume the heap always wins
When k is close to n, O(n log k) and O(n log n) are the same thing, and sorting has a much smaller constant factor. For nums.length = 100, sorting is faster in wall-clock time.
The heap wins on memory and on streams, and on time only when k ≪ n.
Edge Cases
Related Problems
- Top K Frequent Elements — the same size-
kidea, applied to counts instead of values - Merge k Sorted Lists — a heap where the items are list heads
- Heaps — how sift-up and sift-down actually work