import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import java.util.*; /** * Given a non-empty array of integers, return the k most frequent elements. * <p> * For example, * Given [1,1,1,2,2,3] and k = 2, return [1,2]. * <p> * Note: * You may assume k is always valid, 1 ≤ k ≤ number of unique elements. * Your algorithm's time complexity must be better than O(n log n), where n is the array's size. * <p> * Tags: Hash Table, Heap * Similar Problems: (M) Word Frequency, (M) Kth Largest Element in an Array */ public class TopKFrequentElements { private TopKFrequentElements t; /** * Use a map to store frequency. * Create a bucket of lists, indexed by frequency. * Each list contains the number of that frequency. */ public List<Integer> topKFrequent(int[] nums, int k) { if (nums == null || nums.length == 0) return Collections.emptyList(); // Build frequency map Map<Integer, Integer> frequencyMap = new HashMap<>(); for (int n : nums) { frequencyMap.put(n, frequencyMap.getOrDefault(n, 0) + 1); } // Build frequency buckets List<Integer>[] lists = new List[nums.length + 1]; for (Map.Entry<Integer, Integer> e : frequencyMap.entrySet()) { int frequency = e.getValue(); if (lists[frequency] == null) lists[frequency] = new ArrayList<>(); lists[frequency].add(e.getKey()); } // Add top k most frequent integer to result List<Integer> res = new ArrayList<>(); for (int i = lists.length - 1; i >= 0; i--) { if (lists[i] == null) continue; for (int j = 0; j < lists[i].size() && res.size() < k; j++) { res.add(lists[i].get(j)); } } return res; } @Before public void setUp() { t = new TopKFrequentElements(); } @Test public void testInvalidInput() { Assert.assertEquals(Collections.EMPTY_LIST, t.topKFrequent(null, 0)); Assert.assertEquals(Collections.EMPTY_LIST, t.topKFrequent(new int[]{}, 0)); } @Test public void testEdgeCase() { List<Integer> res = t.topKFrequent(new int[]{1}, 1); Assert.assertEquals(1, res.size()); Assert.assertEquals(1, res.get(0).intValue()); } @Test public void testExample() { List<Integer> res = t.topKFrequent(new int[]{1, 1, 1, 2, 2, 3}, 2); Assert.assertEquals(2, res.size()); Assert.assertEquals(1, res.get(0).intValue()); Assert.assertEquals(2, res.get(1).intValue()); } @After public void tearDown() { t = null; } }