DSA Guide
Heaps

Kth Largest Element in an Array

Find the kth largest value without sorting everything, by keeping only the k best candidates in a heap

MediumHeap· size-k min-heap
ArrayHeapSortingDivide and Conquer
Problem #215

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 4

Intuition

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

nums = [3, 2, 1, 5, 6, 4], k = 2
0
3
num
1
2
2
1
3
5
4
6
5
4
heap[3]size1
Push 3. The heap holds 1 item, which is not more than k = 2, so nothing is evicted.
1 / 6
The heap never grew past 2, no matter how long the array was.

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 n values, and each push or pop costs O(log k) because the heap never exceeds k items. When k is small this is very close to O(n).
  • Space — the heap holds at most k values, no matter how large n is. This is the real prize: it lets you handle a stream of numbers too large to hold in memory.

Compared with sorting

ApproachTimeSpaceBest when
Sort, then indexO(n log n)O(n) or O(log n)k is close to n, or the code must be obvious
Min-heap of size kO(n log k)O(k)k is much smaller than n, or the input is a stream
QuickselectO(n) averageO(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

On this page