LeetCode #215 Medium

Kth Largest Element in an Array

Kth Largest Element in an Array is LeetCode 215 (Medium). Given an integer array nums and an integer k, return the k-th largest element: the value at position k if nums were sorted from largest to smallest.

  • Repeated values each count. It is the k-th largest in sorted order, not the k-th distinct value.
  • nums holds up to 10⁵ values between −10⁴ and 10⁴, and 1 ≤ k ≤ n.
  • LeetCode asks whether you can solve it without sorting.
Constraints
  • 1 <= k <= nums.length <= 10⁵
  • -10⁴ <= nums[i] <= 10⁴
heapquickselectarray
Open on LeetCode ↗
02

Intuition

To find the kth largest element in an array you only need the k largest values; the order of everything else never matters.

Keep those k values in a min-heap. Its top is the smallest of them, so it is the value every newcomer has to beat. Once every value has been seen, the heap holds the k largest, and its top is exactly the k-th largest.

How to spot this pattern

"k-th largest" or "top k" over a collection points to a heap of size k that keeps the weakest survivor on top: a min-heap for the largest values, a max-heap for the smallest. K Closest Points to Origin (973) and Top K Frequent Elements (347) follow the same plan.

03

Approach

Try it first

Before reading on, walk [3,2,1,5,6,4] with k = 2, holding only two values at any time. Which of the two should each new value be compared with?

1

Seed the heap with the first k values

Take nums[:k] and turn it into a min-heap; in the kth largest element in an array Python code, heapq.heapify does this in place in O(k). These are the k largest values seen so far, simply because nothing else has been seen yet.

2

Compare every other value with the top

For each remaining num, look at heap[0], the smallest of the current top k:

  • num <= heap[0]: skip it. k values already beat or tie it.
  • num > heap[0]: the top drops out of the top k. heapreplace pops it and pushes num in one O(log k) step.
3

Return the top

After the last value, the heap holds the k largest values and its top is the smallest of them: the k-th largest overall. Repeated values need no special care, because each copy is a separate entry in the heap.

04

Kth Largest Element in an Array solution in Python | C++ | Java

▶1class Solution:
▶2 def findKthLargest(self, nums: List[int], k: int) -> int:
▶3 heap = nums[:k]
▶4 heapq.heapify(heap)
▶5 for num in nums[k:]:
▶6 if num > heap[0]:
▶7 heapq.heapreplace(heap, num)
▶8 return heap[0]
nums302112536445first k = 2heap23topheapify first 2 → top 2
heap[2, 3]k largest so far
top2smallest of them
Seed the heap with the first 2 values. With nothing else seen yet, they are the 2 largest so far. The min-heap keeps the smallest of them, 2, on top: it is the one a newcomer has to beat.
nums302112536445numheap23top1 ≤ top 2 → skip
num1
heap[2, 3]unchanged
1 is smaller than the top 2. All 2 values in the heap are at least as large, so 1 cannot be in the top 2 and is skipped.
nums302112536445numheap35top2 out5 > top 2 → replace, new top 3
num5
out2
heap[3, 5]top 3
5 beats the top 2, so 2 can no longer be among the 2 largest: it leaves and 5 takes its place. The new smallest, 3, moves to the top.
nums302112536445numheap56top3 out6 > top 3 → replace, new top 5
num6
out3
heap[5, 6]top 5
6 beats the top 3, so 3 can no longer be among the 2 largest: it leaves and 6 takes its place. The new smallest, 5, moves to the top.
nums302112536445numheap56top4 ≤ top 5 → skip
num4
heap[5, 6]unchanged
4 is smaller than the top 5. All 2 values in the heap are at least as large, so 4 cannot be in the top 2 and is skipped.
nums302112536445heap56topreturn top → 5
answer5k-th largest
heap[5, 6]the 2 largest
Done. The heap holds the 2 largest values of the whole array, and its top is the smallest of them, so 5 is the 2nd largest.
05

Quickselect (three-way partition)

The k-th largest is the value at index n − k in sorted order. Each round picks a random pivot and splits the current window into smaller, equal and larger parts; if index n − k falls in the equal part the pivot is the answer, otherwise only the side holding it is searched next.

▶1class Solution:
▶2 def findKthLargest(self, nums: List[int], k: int) -> int:
▶3 lo, hi, target = 0, len(nums) - 1, len(nums) - k
▶4 while True:
▶5 pivot = nums[random.randint(lo, hi)]
▶6 lt, i, gt = lo, lo, hi
▶7 while i <= gt:
▶8 if nums[i] < pivot:
▶9 nums[lt], nums[i] = nums[i], nums[lt]
▶10 lt += 1
▶11 i += 1
▶12 elif nums[i] > pivot:
▶13 nums[i], nums[gt] = nums[gt], nums[i]
▶14 gt -= 1
▶15 else:
▶16 i += 1
▶17 if target < lt:
▶18 hi = lt - 1
▶19 elif target > gt:
▶20 lo = gt + 1
▶21 else:
▶22 return nums[target]
06

Common pitfalls

Reading the k-th value from the wrong end

✗ Wrong
nums.sort()
return nums[k - 1]
✓ Right
nums.sort()
return nums[len(nums) - k]

An ascending sort puts the smallest value first, so nums[k - 1] is the k-th smallest. The k-th largest sits k places from the end.

Removing duplicates first

✗ Wrong
nums = list(set(nums))
✓ Right
heap = nums[:k]
heapq.heapify(heap)

The problem counts repeats. For [3,2,3,1,2,4,5,5,6] with k = 4 the answer is 4, but after removing duplicates the 4th largest of {1, …, 6} is 3.

07

Complexity

Time
O(n log k)
Space
O(k)
Heapify costs O(k); each of the other n − k values does at most one O(log k) replace. The input array is never changed.
08

Kth Largest in an Array vs in a Stream

LeetCode 703 has almost the same name, and the same min-heap of size k solves both. The difference is when the answer is needed.

Kth Largest Element in an Array (215)Kth Largest Element in a Stream (703)
Inputone fixed arrayvalues arrive one at a time through add
Answeronce, at the endafter every add
Heapmin-heap of size kmin-heap of size k, kept between calls
Quickselectworksno: it needs all the values at once
09

Kth Largest Element in an Array FAQ

Why does quickselect sometimes time out on LeetCode 215?

The kth largest element in an array LeetCode tests include arrays full of repeated values. A partition with a fixed pivot and only two sides splits such arrays very unevenly, which costs O(n²). A random pivot with a three-way split (smaller, equal, larger), as in the quickselect code on this page, avoids it.