Top K Elements Pattern
🏆 Top K Elements - Find 3 Largest Numbers
Processing Array:
Min Heap (keeps K largest, min on top):
Current Element:
Step 1: Add 3 to min heap
Progress: 1 / 6
Strategy:
Use min heap of size K to track K largest elements. If new element > heap's min, replace it! O(n log k) time vs O(n log n) for sorting.
🎯 Explain Like I'm 5...
Imagine you're collecting the 3 BIGGEST rocks 🪨 from a pile of 10 rocks. You don't need to organize ALL 10 rocks - just keep the 3 biggest!
🎒 Your Magic Bag holds exactly 3 rocks:
- • Pick up first 3 rocks → put them in bag
- • Pick up rock #4 → Is it BIGGER than the smallest rock in your bag?
- • If YES: throw out the smallest, keep the new bigger one! ✅
- • If NO: just drop it, keep your 3 rocks! ❌
- • Keep doing this for ALL rocks!
At the end, your bag has the 3 BIGGEST rocks! 🎉
🚀 Why is it smart? You only remember 3 rocks at a time, not all 10! The magic bag (called a "heap") automatically knows which is the smallest rock to throw out. Super efficient!
When Should You Use This Pattern?
- ✓Finding the top/bottom K elements
- ✓Finding the Kth largest/smallest element
- ✓Problems mentioning "most frequent" or "closest"
- ✓Better than sorting when K << N
📝 Example 1: Kth Largest Element
Find the Kth largest element in an unsorted array.
Step-by-Step Thinking:
- Use a min heap of size K
- Add first K elements to heap
- For remaining elements, if larger than heap's min, replace it
- Heap's top is the Kth largest!
import java.util.*;public class KthLargest { public static int findKthLargest(int[] nums, int k) { // Min heap to keep track of K largest elements PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // Add first k elements for (int i = 0; i < k; i++) { minHeap.offer(nums[i]); } // Process remaining elements for (int i = k; i < nums.length; i++) { // If current element is larger than smallest in heap if (nums[i] > minHeap.peek()) { minHeap.poll(); // Remove smallest minHeap.offer(nums[i]); // Add current } } // Top of min heap is Kth largest return minHeap.peek(); } // Alternative: Using QuickSelect (average O(n)) public static int findKthLargestQuickSelect(int[] nums, int k) { // Convert to find (n-k)th smallest for easier logic return quickSelect(nums, 0, nums.length - 1, nums.length - k); } private static int quickSelect(int[] nums, int left, int right, int k) { if (left == right) return nums[left]; int pivotIndex = partition(nums, left, right); if (k == pivotIndex) { return nums[k]; } else if (k < pivotIndex) { return quickSelect(nums, left, pivotIndex - 1, k); } else { return quickSelect(nums, pivotIndex + 1, right, k); } } private static int partition(int[] nums, int left, int right) { int pivot = nums[right]; int i = left; for (int j = left; j < right; j++) { if (nums[j] <= pivot) { swap(nums, i, j); i++; } } swap(nums, i, right); return i; } private static void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } public static void main(String[] args) { int[] nums = {3, 2, 1, 5, 6, 4}; int k = 2; System.out.println("Kth largest (heap): " + findKthLargest(nums, k)); System.out.println("Kth largest (quickselect): " + findKthLargestQuickSelect(nums, k)); // Output: 5 (second largest) }}📝 Example 2: Top K Frequent Elements
Find the K most frequent elements in an array.
import java.util.*;public class TopKFrequent { public static int[] topKFrequent(int[] nums, int k) { // Step 1: Count frequencies Map<Integer, Integer> freqMap = new HashMap<>(); for (int num : nums) { freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); } // Step 2: Use min heap of size k (ordered by frequency) PriorityQueue<Map.Entry<Integer, Integer>> minHeap = new PriorityQueue<>((a, b) -> a.getValue() - b.getValue()); // Step 3: Keep k most frequent elements in heap for (Map.Entry<Integer, Integer> entry : freqMap.entrySet()) { minHeap.offer(entry); if (minHeap.size() > k) { minHeap.poll(); // Remove least frequent } } // Step 4: Extract results int[] result = new int[k]; for (int i = 0; i < k; i++) { result[i] = minHeap.poll().getKey(); } return result; } public static void main(String[] args) { int[] nums = {1, 1, 1, 2, 2, 3}; int k = 2; int[] result = topKFrequent(nums, k); System.out.println("Top " + k + " frequent: " + Arrays.toString(result)); // Output: [1, 2] (1 appears 3 times, 2 appears 2 times) }}📝 Example 3: K Closest Points to Origin
Find K points closest to the origin (0, 0) in a 2D plane.
import java.util.*;public class KClosestPoints { public static int[][] kClosest(int[][] points, int k) { // Max heap based on distance (keep k closest) PriorityQueue<int[]> maxHeap = new PriorityQueue<>( (a, b) -> (b[0] * b[0] + b[1] * b[1]) - (a[0] * a[0] + a[1] * a[1]) ); // Add points to heap for (int[] point : points) { maxHeap.offer(point); // Keep only k closest points if (maxHeap.size() > k) { maxHeap.poll(); } } // Extract k closest points int[][] result = new int[k][2]; for (int i = 0; i < k; i++) { result[i] = maxHeap.poll(); } return result; } public static void main(String[] args) { int[][] points = {{1, 3}, {-2, 2}, {5, 8}, {0, 1}}; int k = 2; int[][] result = kClosest(points, k); System.out.println("K closest points:"); for (int[] point : result) { System.out.println("[" + point[0] + ", " + point[1] + "]"); } // Output: [0, 1] and [-2, 2] or [1, 3] // (distances: 1, 8, 89, 10) }}🔑 Key Points to Remember
- 1️⃣Use min heap for K largest, max heap for K smallest
- 2️⃣Keep heap size at K - don't let it grow beyond!
- 3️⃣Time Complexity: O(n log k) vs O(n log n) for full sort
- 4️⃣Space Complexity: O(k) for the heap
💪 Practice Problems
- • K Closest Numbers
- • Rearrange String K Distance Apart
- • Reorganize String
- • Frequency Stack
- • Kth Largest in Stream