题目描述

image.png

解题思路

根据频率大小排序,那么可以使用哈希表来对频率进行统计,在对频率进行排序。
那么问题来了,定义一个大小为k的大顶堆,在每次移动更新大顶堆的时候,每次弹出都把最大的元素弹出去了,那么怎么保留下来前K个高频元素呢。
而且使用大顶堆就要把所有元素都进行排序,那能不能只排序k个元素呢?
所以我们要用小顶堆,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。
image.png

  1. /**
  2. * 使用小顶堆实现
  3. *
  4. * @param nums
  5. * @param k
  6. * @return
  7. */
  8. public int[] topKFrequent(int[] nums, int k) {
  9. int[] res = new int[k];
  10. HashMap<Integer, Integer> map = new HashMap<>();
  11. // 将出现的值和频率使用map封装
  12. for (int i = 0; i < nums.length; i++) {
  13. map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
  14. }
  15. // 放入集合中方便遍历到队列中
  16. Set<Map.Entry<Integer, Integer>> entries = map.entrySet();
  17. // 创建优先队列(小顶堆)
  18. PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<Map.Entry<Integer, Integer>>((o1, o2) -> {
  19. return o1.getValue() - o2.getValue();
  20. });
  21. // 将map入队
  22. for (Map.Entry<Integer, Integer> entry : entries) {
  23. queue.offer(entry);
  24. // 如果队列中的个数大于k,需要将多余的出队,此时是小顶堆,最小的在队首,所以直接出队即可
  25. if (queue.size() > k) {
  26. queue.poll();
  27. }
  28. }
  29. // 取出队列中的所有元素,即为频率前k个元素
  30. for (int i = 0; i < k; i++) {
  31. res[i] = queue.poll().getKey();
  32. }
  33. return res;
  34. }