Sale: Get 60% Off on all Pro Plans. Buy Now

Kth Largest Element in a Stream

Problem

Design a class to find the kth largest element in a stream of integers, supporting adding new elements and retrieving the kth largest element efficiently.

  • 1 ≤ k ≤ 10⁴
  • 0 ≤ nums.length ≤ 10⁴
  • −10⁴ ≤ nums[i] ≤ 10⁴
  • −10⁴ ≤ val ≤ 10⁴
  • At most 10⁴ calls will be made to add.
  • It is guaranteed that there will be at least k elements in the stream when you search for the kth largest element.

Example

Input: k = 3, nums = [4,5,8,2], add(3), add(5), add(10), add(9), add(4)
Output: [null, 4, 5, 5, 8, 8]

Initially, the stream is [4,5,8,2]. The 3rd largest element is 4. After add(3), stream is [4,5,8,2,3], 3rd largest is 4. After add(5), stream is [4,5,8,2,3,5], 3rd largest is 5. After add(10), stream is [4,5,8,2,3,5,10], 3rd largest is 5. After add(9), stream is [4,5,8,2,3,5,10,9], 3rd largest is 8. After add(4), stream is [4,5,8,2,3,5,10,9,4], 3rd largest is 8.

Approach

Straightforward Solution

A naive approach is to keep all elements in a list and sort it after each insertion, resulting in O(n log n) time per add call, which is inefficient for large streams.

Core Observation

The kth largest element in a stream is the element that would be at index len(stream) - k if the stream were sorted. Maintaining a full sorted list after each insertion is inefficient. Instead, a min-heap of size k can track the top k largest elements, with the smallest among them at the root representing the kth largest overall.

Path to Optimal

Preview

The key recognition signals are 'kth largest element', 'stream', and 'add elements dynamically'. These indicate a heap or priority queue pattern because a heap can efficiently maintain the top k elements with O(log k) insertion and removal…

Full step-by-step walkthrough on Pro

Optimal Approach

Preview

Initialize a min-heap with the first k elements from nums (or fewer if nums has less than k elements), popping the smallest elements until the heap size is k. For each add(val), push val into the heap and pop the smallest element if the heap exceeds size k…

Full step-by-step walkthrough on Pro

Want the full reasoning chain?

Unlock the complete walkthrough, line-by-line analysis, and recall drill.

Unlock Pro

Time

O(n log k) for initialization and O(log k) per add call

Heapifying the initial list takes O(n), but popping elements to maintain size k costs O((n-k) log n). Each add operation involves a push and possibly a pop on a heap of size k, each O(log k).

Space

O(k)

The min-heap stores at most k elements at any time, so auxiliary space scales linearly with k, independent of the total number of elements added.

Pattern Spotlight

Heap / Priority Queue (Fixed-Size Min-Heap for Top K Elements)

Maintain a min-heap of size k to track the top k largest elements; the heap root always represents the kth largest, enabling efficient updates and queries in a dynamic stream.

Solution

Python
1import heapq
2
3class KthLargest:
4 def __init__(self, k: int, nums: list[int]):
5 self.min_heap = nums
6 self.k = k
7 heapq.heapify(self.min_heap)
8 while len(self.min_heap) > k:
9 heapq.heappop(self.min_heap)
10
11 def add(self, val: int) -> int:
12 heapq.heappush(self.min_heap, val)
13 if len(self.min_heap) > self.k:
14 heapq.heappop(self.min_heap)
15 return self.min_heap[0]

Step-by-Step Solution

1

Build and Maintain a Min-Heap of Size k from Initial Stream

5self.min_heap = nums
6self.k = k
7heapq.heapify(self.min_heap)
8while len(self.min_heap) > k:
9 heapq.heappop(self.min_heap)

Objective

To initialize the min-heap with the k largest elements from the initial list, ensuring efficient retrieval of the kth largest element.

Key Insight

Heapifying the initial list transforms it into a valid min-heap in O(n) time. Removing elements until the heap size is k discards smaller elements, leaving only the top k largest. This setup guarantees that the heap root is the kth largest element before any additions.

Interview Quick-Check

Core Logic

Heapify the input list to create a min-heap, then pop the smallest elements until only k remain, ensuring the heap contains the k largest elements.

State & Boundaries

Maintain the heap size at most k to keep the kth largest element at the root.

Common Pitfalls & Bugs

Failing to reduce the heap size to k after heapify can cause incorrect kth largest results.

2

Add New Elements and Adjust Heap to Maintain kth Largest

To insert new elements into the min-heap and remove the smallest if the heap exceeds size k, preserving the kth largest element at the root.

1 more step with full analysis available on Pro.

Line Analysis

This solution has 4 Critical lines interviewers watch for.

Line 7 Critical
heapq.heapify(self.min_heap)

Transform the list min_heap into a valid min-heap in-place.

Heapifying the list in O(n) time prepares it for efficient insertion and removal operations, enabling the heap to maintain the top k elements dynamically.

Line 8 Critical
while len(self.min_heap) > k:

While the heap size exceeds k, remove the smallest element.

This loop ensures the heap only contains the k largest elements by discarding smaller ones, which is essential for the heap root to represent the kth largest element.

Line 13 Critical
if len(self.min_heap) > self.k:

If the heap size exceeds k, remove the smallest element.

This conditional removal keeps the heap size fixed at k, ensuring the root remains the kth largest element after the addition.

Full line-by-line criticality + rationale for all 9 lines available on Pro.

Test Your Understanding

Why does maintaining a min-heap of size k guarantee that the root is the kth largest element in the stream?

See the answer with Pro.

Related Problems

Heap / Priority Queue pattern

Don't just read it. Drill it.

Reconstruct Kth Largest Element in a Stream from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.

Unlock the Kth Largest Element in a Stream drill

or drill a free problem