You need the kth largest value without fully sorting. A size-k min-heap scans the array once and keeps the top-k elements at O(log k) cost per element — or go one step further with Quickselect for O(n) average time.
Given an integer array nums and an integer k, return the kth largest element in the array (not the kth distinct element). Example: nums = [3,2,1,5,6,4], k = 2 → sorted descending is [6,5,4,3,2,1], so the 2nd largest is 5. Another: nums = [3,2,3,1,2,4,5,5,6], k = 4 → 4.
k elements. Maintain a min-heap capped at size k. The root (minimum of the heap) is always the current kth largest. If a new element beats the root, swap it in; otherwise skip. After one pass the root is the answer — no full sort needed.Approach A — min-heap O(n log k):
k. This preserves exactly the top-k elements.heap[0] — the smallest of the top-k is the kth largest overall.Approach B — Quickselect O(n) average:
k-1).k-1 — discard the other half entirely.k-1.Quickselect achieves O(n) average with O(1) extra space (in-place partition), but O(n²) worst case on adversarial inputs. A randomized pivot (shuffle or random pick) makes worst case vanishingly rare. The heap approach is deterministic and often preferred in interviews for clarity.
2th largest in [3, 2, 1, 5, 6, 4]. We push every element into a min-heap, evicting the minimum whenever the heap exceeds size 2. The root is always our answer candidate.1▶function findKthLargest(nums: number[], k: number): number {2▶ // Min-heap of size k — the root is always the kth largest seen so far.3▶ const heap: number[] = [];45 function push(val: number): void {6 heap.push(val);7 let i = heap.length - 1;8 while (i > 0) {9 const p = Math.floor((i - 1) / 2);10 if (heap[p] > heap[i]) { [heap[p], heap[i]] = [heap[i], heap[p]]; i = p; }11 else break;12 }13 }1415 function pop(): number {16 const top = heap[0];17 const last = heap.pop()!;18 if (heap.length > 0) {19 heap[0] = last;20 let i = 0;21 while (true) {22 const l = 2 * i + 1, r = 2 * i + 2;23 let s = i;24 if (l < heap.length && heap[l] < heap[s]) s = l;25 if (r < heap.length && heap[r] < heap[s]) s = r;26 if (s === i) break;27 [heap[i], heap[s]] = [heap[s], heap[i]]; i = s;28 }29 }30 return top;31 }3233 for (const n of nums) {34 push(n); // add every element35 if (heap.length > k) pop(); // evict the minimum when over-full36 }37 return heap[0]; // root = kth largest38}
function findKthLargest(nums: number[], k: number): number {
// Min-heap of size k — the root is always the kth largest seen so far.
const heap: number[] = [];
function push(val: number): void {
heap.push(val);
let i = heap.length - 1;
while (i > 0) {
const p = Math.floor((i - 1) / 2);
if (heap[p] > heap[i]) { [heap[p], heap[i]] = [heap[i], heap[p]]; i = p; }
else break;
}
}
function pop(): number {
const top = heap[0];
const last = heap.pop()!;
if (heap.length > 0) {
heap[0] = last;
let i = 0;
while (true) {
const l = 2 * i + 1, r = 2 * i + 2;
let s = i;
if (l < heap.length && heap[l] < heap[s]) s = l;
if (r < heap.length && heap[r] < heap[s]) s = r;
if (s === i) break;
[heap[i], heap[s]] = [heap[s], heap[i]]; i = s;
}
}
return top;
}
for (const n of nums) {
push(n); // add every element
if (heap.length > k) pop(); // evict the minimum when over-full
}
return heap[0]; // root = kth largest
}push appends then sifts up by swapping with parent while parent is larger (min-heap invariant: parent ≤ child). pop removes the root, moves the last leaf to the top, then sifts down — swap with the smaller child to restore the invariant.k, evict the current minimum. This guarantees the heap always holds at most k elements and they are the k largest seen so far.k-1. Randomize the pivot to avoid O(n²) worst case.function findKthLargest(nums: number[], k: number): number {
// Min-heap of size k — the root is always the kth largest seen so far.
const heap: number[] = [];
function push(val: number): void {
heap.push(val);
let i = heap.length - 1;
while (i > 0) {
const p = Math.floor((i - 1) / 2);
if (heap[p] > heap[i]) { [heap[p], heap[i]] = [heap[i], heap[p]]; i = p; }
else break;
}
}
function pop(): number {
const top = heap[0];
const last = heap.pop()!;
if (heap.length > 0) {
heap[0] = last;
let i = 0;
while (true) {
const l = 2 * i + 1, r = 2 * i + 2;
let s = i;
if (l < heap.length && heap[l] < heap[s]) s = l;
if (r < heap.length && heap[r] < heap[s]) s = r;
if (s === i) break;
[heap[i], heap[s]] = [heap[s], heap[i]]; i = s;
}
}
return top;
}
for (const n of nums) {
push(n); // add every element
if (heap.length > k) pop(); // evict the minimum when over-full
}
return heap[0]; // root = kth largest
}Sort the whole array descending and read off the element at position k − 1 — the kth largest. A clean correctness baseline before reaching for a heap or quickselect.
function findKthLargest(nums: number[], k: number): number {
// Sort descending; the kth largest is then at index k - 1.
nums.sort((a, b) => b - a);
return nums[k - 1];
}O(n log n) work to fully order every element when we only need the kth. A size-k min-heap brings it to O(n log k), and quickselect averages O(n).| "kth largest / kth smallest" | bounded min-heap (or max-heap) of size k |
| "top-k elements" | min-heap of size k; root = answer |
| "O(n) selection" | Quickselect — partition then recurse one side |
| "streaming kth largest" | persistent size-k min-heap, O(log k) per insert |
function findKthLargest(nums: number[], k: number): number {
const heap: number[] = [];
// push with sift-up; pop with sift-down
for (const n of nums) {
push(n);
if (heap.length > k) pop(); // evict the min when heap exceeds k
}
return heap[0]; // root = kth largest
}k?nums = [3,2,1,5,6,4], k = 2 with the heap approach. What does the heap contain after processing all six elements?k-1 in descending order), after partitioning around a pivot at position p, you should: