所谓的top-k问题就是求一组数据中 前k个最大或者最小的元素
本篇文章以 求前k个最大的元素 为例
建立大根堆还是小根堆?
首先,求前k个最大的元素 是建立大根堆还是小根堆呢?
答案是建立小根堆
为什么建立小根堆呢?
如果我们要找上图数组中前三个最大的元素
首先给前三个元素建立大根堆 也就是
解释:之所以建立小根堆是因为 小根堆的堆顶元素是最小的,如果在数组 k个元素后面遍历的时候遇到比堆顶元素还要小的值,那么就没必要入堆。也就是堆顶元素本来就很小了,来了个比它还要小的,那么我入它干嘛对不对
代码如下
public int[] maxK(int[] arr, int k) { //TOP-K问题 int[] ret = new int[k]; if(arr == null || k == 0) { return null; } Queue<Integer> minHeap = new PriorityQueue<>(k); //1.遍历数组的前k个元素,放到堆中 for (int i = 0; i < k; i++) { minHeap.offer(arr[i]); } //2.遍历剩下的K - 1 个,每次和栈顶元素进行比较 for (int j = k; j < arr.length; j++) { if(!minHeap.isEmpty() && arr[j] > minHeap.peek()) { minHeap.poll(); //堆顶元素小的时候就出栈 minHeap.offer(arr[j]); //放进来 } } for (int i = 0; i < k; i++) { ret[i] = minHeap.poll(); } return ret; } }
第一步 初始化小根堆
第二步 遍历数组的前k个元素,将这前k个元素建立成小根堆
第三步 遍历剩下的k - 1 个,每次和栈顶元素进行比较,新元素比栈顶元素小不入堆,反之入堆