Chaturmind
LearnDSASystem DesignBlogPremium
Sign inGet started
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML

Company

  • Blog
  • Premium
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Interview Coding Patterns

Core Patterns

  • Fast & Slow Pointers
  • Merge Intervals
  • Cyclic Sort

Heap & Priority Queue Patterns

  • Top-K Elements
  • K-Way Merge
  • Two Heaps
Chaturmind
← Interview Coding Patterns

Core Patterns

  • Fast & Slow Pointers
  • Merge Intervals
  • Cyclic Sort

Heap & Priority Queue Patterns

  • Top-K Elements
  • K-Way Merge
  • Two Heaps
HomeLearnDSADSA Patterns for InterviewsCoding Patterns
✓ FreeIntermediate· 13 min read

Top K Elements

Use min-heap, max-heap, and QuickSelect to find kth largest, top k frequent, and k closest elements.

Published March 24, 2025


Top K Elements

Problems asking for the k largest, k smallest, or k most frequent elements are efficiently solved with heaps or QuickSelect.

Kth Largest Element — Min-Heap

// Maintain a min-heap of size k — the root is the kth largest
public int findKthLargest(int[] nums, int k) {
    PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // min at top
    for (int num : nums) {
        minHeap.offer(num);
        if (minHeap.size() > k) minHeap.poll(); // remove smallest
    }
    return minHeap.peek(); // kth largest is the smallest in heap of size k
}
// Time: O(n log k), Space: O(k)

Kth Largest — QuickSelect (O(n) average)

public int findKthLargest(int[] nums, int k) {
    return quickSelect(nums, 0, nums.length - 1, nums.length - k);
}
int quickSelect(int[] nums, int lo, int hi, int targetIdx) {
    int pivot = nums[hi];
    int p = lo;
    for (int i = lo; i < hi; i++)
        if (nums[i] <= pivot) swap(nums, i, p++);
    swap(nums, p, hi);

    if (p == targetIdx) return nums[p];
    return p < targetIdx
        ? quickSelect(nums, p+1, hi, targetIdx)
        : quickSelect(nums, lo, p-1, targetIdx);
}
void swap(int[] a, int i, int j) { int t = a[i]; a[i] = a[j]; a[j] = t; }
// Time: O(n) average, O(n²) worst

Top K Frequent Elements

public int[] topKFrequent(int[] nums, int k) {
    Map<Integer, Integer> freq = new HashMap<>();
    for (int n : nums) freq.merge(n, 1, Integer::sum);

    // Min-heap by frequency
    PriorityQueue<int[]> heap = new PriorityQueue<>((a,b) -> a[1] - b[1]);
    for (Map.Entry<Integer, Integer> e : freq.entrySet()) {
        heap.offer(new int[]{e.getKey(), e.getValue()});
        if (heap.size() > k) heap.poll();
    }

    int[] result = new int[k];
    for (int i = k-1; i >= 0; i--) result[i] = heap.poll()[0];
    return result;
    // Time: O(n log k)
}

Bucket Sort Approach for Top K Frequent — O(n)

public int[] topKFrequent(int[] nums, int k) {
    Map<Integer, Integer> freq = new HashMap<>();
    for (int n : nums) freq.merge(n, 1, Integer::sum);

    // Bucket: index = frequency
    List<Integer>[] bucket = new List[nums.length + 1];
    for (Map.Entry<Integer, Integer> e : freq.entrySet()) {
        int f = e.getValue();
        if (bucket[f] == null) bucket[f] = new ArrayList<>();
        bucket[f].add(e.getKey());
    }

    List<Integer> result = new ArrayList<>();
    for (int f = bucket.length - 1; f >= 0 && result.size() < k; f--)
        if (bucket[f] != null) result.addAll(bucket[f]);

    return result.stream().mapToInt(Integer::intValue).toArray();
}

K Closest Points to Origin

public int[][] kClosest(int[][] points, int k) {
    // Max-heap by distance — keep the k smallest
    PriorityQueue<int[]> maxHeap = new PriorityQueue<>(
        (a, b) -> (b[0]*b[0]+b[1]*b[1]) - (a[0]*a[0]+a[1]*a[1]));
    for (int[] p : points) {
        maxHeap.offer(p);
        if (maxHeap.size() > k) maxHeap.poll(); // remove furthest
    }
    return maxHeap.toArray(new int[0][]);
}

Sort Characters By Frequency

public String frequencySort(String s) {
    Map<Character, Integer> freq = new HashMap<>();
    for (char c : s.toCharArray()) freq.merge(c, 1, Integer::sum);

    PriorityQueue<Map.Entry<Character, Integer>> maxHeap =
        new PriorityQueue<>((a, b) -> b.getValue() - a.getValue());
    maxHeap.addAll(freq.entrySet());

    StringBuilder sb = new StringBuilder();
    while (!maxHeap.isEmpty()) {
        Map.Entry<Character, Integer> e = maxHeap.poll();
        sb.append(String.valueOf(e.getKey()).repeat(e.getValue()));
    }
    return sb.toString();
}

Interview Tips

  1. When k << n: use a heap of size k → O(n log k). Better than full sort O(n log n).
  2. When you need exact kth: QuickSelect gives O(n) average — but expect follow-up about worst case.
  3. Know the PriorityQueue default in Java is a min-heap — for max-heap use (a, b) -> b - a.

Previous

Cyclic Sort

Next

K-Way Merge

AI Tutor

Lesson: Top K Elements

Quick actions

AI responses can be inaccurate. Verify critical information.