HeapProblem 4 of 18
k largest element in an array
Problem Statement
Given an array of integers, find the K largest elements in the array.
Example:
- Input:
arr = [1, 23, 12, 9, 30, 2, 50],k = 3 - Output:
[50, 30, 23] - Explanation: The 3 largest elements are 50, 30, and 23.
Approach 1: Sorting (Brute Force)
Intuition
Sort the array in descending order and return the first K elements.
Algorithm
- Sort the array in descending order
- Return the first K elements
java
import java.util.Arrays;
import java.util.Collections;
public class Solution {
public int[] kLargestElements(int[] arr, int k) {
Integer[] boxed = Arrays.stream(arr).boxed().toArray(Integer[]::new);
Arrays.sort(boxed, Collections.reverseOrder());
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = boxed[i];
}
return result;
}
}Complexity Analysis
- Time Complexity: O(n log n) - Due to sorting
- Space Complexity: O(1) - In-place sorting (ignoring output array)
Approach 2: Using Min-Heap of Size K
Intuition
Maintain a min-heap of size K. The heap always contains the K largest elements seen so far. For each new element, if it's larger than the heap's minimum, replace the minimum.
Algorithm
- Create a min-heap with first K elements
- For remaining elements:
- If element > heap top, pop top and push element
- Heap contains K largest elements
java
import java.util.PriorityQueue;
import java.util.ArrayList;
import java.util.Collections;
public class Solution {
public int[] kLargestElements(int[] arr, int k) {
// Min-heap
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
for (int num : arr) {
minHeap.offer(num);
if (minHeap.size() > k) {
minHeap.poll();
}
}
// Extract elements
int[] result = new int[k];
for (int i = k - 1; i >= 0; i--) {
result[i] = minHeap.poll();
}
return result;
}
}Complexity Analysis
- Time Complexity: O(n log k) - Each insertion/deletion in heap of size k is O(log k)
- Space Complexity: O(k) - Heap stores k elements
Approach 3: Using Max-Heap (Optimal for small K)
Intuition
Build a max-heap from the entire array, then extract K elements.
Algorithm
- Build max-heap from array - O(n)
- Extract maximum K times - O(k log n)
java
import java.util.PriorityQueue;
import java.util.Collections;
public class Solution {
public int[] kLargestElements(int[] arr, int k) {
// Max-heap
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
for (int num : arr) {
maxHeap.offer(num);
}
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = maxHeap.poll();
}
return result;
}
}Complexity Analysis
- Time Complexity: O(n + k log n) - Building heap O(n), k extractions O(k log n)
- Space Complexity: O(n) - Heap contains all elements
Approach 4: QuickSelect Variation
Intuition
Use QuickSelect to partition array such that the K largest elements are in the last K positions.
Algorithm
- Use QuickSelect to find the (n-k)th smallest element
- All elements after this pivot are the K largest
java
import java.util.Arrays;
import java.util.Random;
public class Solution {
private Random rand = new Random();
private int partition(int[] arr, int low, int high) {
// Random pivot
int randIdx = low + rand.nextInt(high - low + 1);
int temp = arr[randIdx];
arr[randIdx] = arr[high];
arr[high] = temp;
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] <= pivot) {
i++;
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1;
}
private void quickSelect(int[] arr, int low, int high, int k) {
if (low >= high) return;
int pivotIdx = partition(arr, low, high);
if (pivotIdx == k) {
return;
} else if (pivotIdx > k) {
quickSelect(arr, low, pivotIdx - 1, k);
} else {
quickSelect(arr, pivotIdx + 1, high, k);
}
}
public int[] kLargestElements(int[] arr, int k) {
int n = arr.length;
int[] arrCopy = arr.clone();
// Find position n-k
quickSelect(arrCopy, 0, n - 1, n - k);
// Extract k largest
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = arrCopy[n - k + i];
}
// Sort descending
Arrays.sort(result);
for (int i = 0; i < k / 2; i++) {
int temp = result[i];
result[i] = result[k - 1 - i];
result[k - 1 - i] = temp;
}
return result;
}
}Complexity Analysis
- Time Complexity: O(n) average, O(n²) worst case
- Space Complexity: O(1) - In-place (O(log n) recursion stack)
Key Takeaways
- Sorting is simplest but not optimal for small K relative to N
- Min-heap of size K is best when K << N: O(n log k) time, O(k) space
- Max-heap is better when K is close to N: O(n + k log n) time
- QuickSelect gives O(n) average but O(n²) worst case
- For K largest, use min-heap; for K smallest, use max-heap
- Python's
heapq.nlargest(k, arr)uses an optimized heap algorithm - Choice depends on K/N ratio and whether sorted output is needed