Lesson 118 of 250
215. Kth Largest Element in an Array
NeetCode: Kth Largest Element in an Array · LeetCode: 215. Kth Largest Element in an Array · Difficulty: Medium
Return the k-th largest element of an unsorted array (the k-th in sorted order, not the k-th distinct value).
Example
Input: nums = [2, 3, 1, 5, 4], k = 2 Output: 4
Input: nums = [2, 3, 1, 2, 4, 2], k = 4 Output: 2Brute force: sort
Arrays.sort on an int[] sorts ascending, so the k-th largest is at index n - k. The code sorts a clone so the caller's array is not reordered.
import java.util.Arrays;
class Solution {
public int findKthLargest(int[] nums, int k) {
int[] sorted = nums.clone();
Arrays.sort(sorted); // ascending
return sorted[sorted.length - k];
}
}
public class Main {
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(s.findKthLargest(new int[]{2, 3, 1, 5, 4}, 2));
System.out.println(s.findKthLargest(new int[]{2, 3, 1, 2, 4, 2}, 4));
}
}4
2Time: O(n log n). Space: O(n).
Better: a min-heap of size k
Same idea as Kth Largest Element in a Stream: keep the k largest values in a min-heap and read its top. Java's PriorityQueue is a min-heap by default.
import java.util.PriorityQueue;
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> heap = new PriorityQueue<>(); // min-heap
for (int x : nums) {
heap.add(x);
if (heap.size() > k) {
heap.poll();
}
}
return heap.peek();
}
}
public class Main {
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(s.findKthLargest(new int[]{2, 3, 1, 5, 4}, 2));
System.out.println(s.findKthLargest(new int[]{2, 3, 1, 2, 4, 2}, 4));
}
}4
2Time: O(n log k). Space: O(k).
Optimal on average: quickselect
The k-th largest is the element at index n - k once sorted. Quickselect partitions like quicksort (the code works on a copy of the array), but recurses into only the side that contains the target index, so the expected work is n + n/2 + n/4 + ... = O(n). The pivot is the middle element, which handles already-sorted input well.
class Solution {
private int partition(int[] nums, int lo, int hi) {
int mid = lo + (hi - lo) / 2;
swap(nums, mid, hi);
int pivot = nums[hi];
int store = lo;
for (int i = lo; i < hi; i++) {
if (nums[i] < pivot) {
swap(nums, i, store);
store++;
}
}
swap(nums, store, hi);
return store;
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public int findKthLargest(int[] nums, int k) {
int[] a = nums.clone();
int target = a.length - k;
int lo = 0, hi = a.length - 1;
while (true) {
int p = partition(a, lo, hi);
if (p == target) {
return a[p];
} else if (p < target) {
lo = p + 1;
} else {
hi = p - 1;
}
}
}
}
public class Main {
public static void main(String[] args) {
Solution s = new Solution();
System.out.println(s.findKthLargest(new int[]{2, 3, 1, 5, 4}, 2));
System.out.println(s.findKthLargest(new int[]{2, 3, 1, 2, 4, 2}, 4));
System.out.println(s.findKthLargest(new int[]{7}, 1));
}
}4
2
7Time: O(n) on average, O(n²) in the worst case. Space: O(1) extra; the array is partitioned in place.
The worst case occurs when every pivot is close to the minimum or maximum. A random pivot makes that unlikely. The partition above also degrades to O(n²) when every element is equal, because no element is smaller than the pivot and each pass removes only one element; the heap version's O(n log k) is the guaranteed bound.
