Loading problems...
TL;DR: Maintain a Min-Heap of size exactly containing the largest elements seen so far; the root of this heap is always the -th largest element.
The problem requires designing a class that processes a continuous stream of test scores. We must initialize the class with an integer and an initial array of scores. The core functionality is the add method, which accepts a new score and returns the -th largest score among all scores seen up to that point (including the initial set and all subsequent additions). This is a classic example of processing data in a stream where the full dataset changes dynamically.
This problem, "LeetCode 703", is a popular interview question because it tests the ability to manage dynamic data efficiently without resorting to repeated sorting.
A naive approach is to store all elements in a dynamic array (like a standard List or Vector). Whenever a new element is added via the add method, we append it to the list. To find the -th largest element, we sort the entire list in descending order and return the element at index .
Pseudo-code:
textClass KthLargest: List store int k Constructor(k, nums): this.k = k this.store = copy(nums) add(val): store.append(val) store.sort(descending) return store[k-1]
Complexity Analysis:
add call, where is the current number of elements in the stream. If we perform add operations, the total time complexity approaches .Why it fails:
The sorting operation is expensive. As the stream grows, increases. With up to calls to add, repeatedly sorting a growing array will result in a Time Limit Exceeded (TLE) error. We need a solution that finds the -th largest element in logarithmic time relative to , rather than linear or log-linear time relative to .
The key intuition is to realize that to determine the -th largest element, we do not need to keep track of the smaller elements that fall below the top threshold. We only need to maintain the "elite" set of the largest scores.
Within this elite set of elements, the smallest element is the -th largest element of the entire stream. For example, if and the top 3 scores are , then is the 3rd largest score overall.
Therefore, we need a data structure that:
A Min-Heap of size satisfies these requirements. By maintaining a Min-Heap with exactly elements (the largest seen so far), the root of the heap (the minimum of the heap) will always correspond to the -th largest element globally.
Visual Description: Imagine the heap as a container with a capacity of . As the stream flows, new numbers attempt to enter the container.

Let's trace k = 3, initial stream [4, 5, 8, 2].
Initialization:
[4][4, 5][4, 5, 8] (Size is 3, limit is 3. Root is 4)[2, 4, 8, 5] -> Size 4 > 3. Pop min (2). Heap [4, 5, 8]. Root is 4.{4, 5, 8}.add(3):
[3, 4, 8, 5][4, 5, 8].add(5):
[4, 5, 8, 5][5, 5, 8].add(10):
[5, 5, 8, 10][5, 8, 10].add(9):
[5, 8, 10, 9][8, 9, 10].The correctness relies on the properties of the Min-Heap.
cpp#include <vector> #include <queue> #include <functional> using namespace std; class KthLargest { private: // Min-heap to store the k largest elements priority_queue<int, vector<int>, greater<int>> minHeap; int k; public: KthLargest(int k, vector<int>& nums) { this->k = k; // Initialize heap with existing numbers for (int num : nums) { add(num); } } int add(int val) { minHeap.push(val); // If heap size exceeds k, remove the smallest element // This ensures the heap only holds the k largest elements if (minHeap.size() > k) { minHeap.pop(); } // The top of the min-heap is the kth largest element return minHeap.top(); } };
javaimport java.util.PriorityQueue; class KthLargest { private PriorityQueue<Integer> minHeap; private int k; public KthLargest(int k, int[] nums) { this.k = k; // Min-heap by default in Java this.minHeap = new PriorityQueue<>(); for (int num : nums) { add(num); } } public int add(int val) { minHeap.offer(val); // Maintain exactly k elements (or fewer if total elements < k) if (minHeap.size() > k) { minHeap.poll(); } return minHeap.peek(); } }
pythonimport heapq class KthLargest: def __init__(self, k: int, nums: list[int]): self.k = k self.min_heap = [] # Process initial numbers for num in nums: self.add(num) def add(self, val: int) -> int: # Push new value to heap heapq.heappush(self.min_heap, val) # If we have more than k elements, remove the smallest if len(self.min_heap) > self.k: heapq.heappop(self.min_heap) # The smallest of the k largest elements is the answer return self.min_heap[0]
Let be the number of elements processed so far and be the rank parameter.
The "Heap - Top K Elements" pattern is versatile. The logic used in LeetCode 703 applies directly to:
Understanding the invariant of the Min-Heap size allows you to solve almost any "Top K" problem efficiently.
Why does the naive solution TLE?
add function.Why not use a Max-Heap?
Why limit the heap size to k?