剑指 Offer II 060. 出现频率最高的 k 个数字(347. 前 K 个高频元素)
题目:
思路:
【1】其实我觉得吧,这个题有点问题,说是必须优于O(n log n),那么是不是就是禁止使用堆了呢,优先队列里面使用的不就是堆排序的思想?那么时间复杂度也为O(n log n),这不就是禁止使用了。神神叨叨不干人事
代码展示:
//时间12 ms击败89.10% //内存44.3 MB击败12.22% //时间复杂度:O(Nlogk),其中 N 为数组的长度。 //首先遍历原数组,并使用哈希表记录出现次数,每个元素需要 O(1) 的时间,共需 O(N) 的时间。 //随后,我们遍历「出现次数数组」,由于堆的大小至多为 k,因此每次堆操作需要 O(logk) 的时间,共需 O(Nlogk) 的时间。 //二者之和为 O(Nlogk)。 //空间复杂度:O(N)。哈希表的大小为 O(N),而堆的大小为 O(k),共计为 O(N)。 class Solution { public int[] topKFrequent(int[] nums, int k) { Map<Integer, Integer> occurrences = new HashMap<Integer, Integer>(); for (int num : nums) { occurrences.put(num, occurrences.getOrDefault(num, 0) + 1); } // int[] 的第一个元素代表数组的值,第二个元素代表了该值出现的次数 PriorityQueue<int[]> queue = new PriorityQueue<int[]>(new Comparator<int[]>() { public int compare(int[] m, int[] n) { return m[1] - n[1]; } }); for (Map.Entry<Integer, Integer> entry : occurrences.entrySet()) { int num = entry.getKey(), count = entry.getValue(); if (queue.size() == k) { if (queue.peek()[1] < count) { queue.poll(); queue.offer(new int[]{num, count}); } } else { queue.offer(new int[]{num, count}); } } int[] ret = new int[k]; for (int i = 0; i < k; ++i) { ret[i] = queue.poll()[0]; } return ret; } } //优化版本 //时间4 ms击败99.68% //内存43.9 MB击败64.7% class Solution { public int[] topKFrequent(int[] nums, int k) { int max = Integer.MIN_VALUE,min = Integer.MAX_VALUE; for (int num : nums) { max = Math.max(max,num); min = Math.min(min,num); } //这里虽说是可能会出现new 一个Integer.MAX_VALUE大小的数组,但是操作上会比使用hashMap要快 int[] res = new int[max - min + 1]; for (int num : nums) res[num - min]++; Queue<int[]> queue = new PriorityQueue<>((a,b)->(b[1] - a[1])); for (int i = 0; i < res.length; i++) { queue.add(new int[]{i + min,res[i]}); } int[] ans = new int[k]; for (int i = 0; i < k; i++) { ans[i] = queue.poll()[0]; } return ans; } }