优先级队列解决TopK问题

  首先我们需要了解什么是TopK问题,那就是给你一个一组数据,数据可能很少或者很多,让你找到前K小或者前K大的数据。当数据比较少的时候我们可以使用暴力解法,那就是直接对整个数据进行排序处理,然后取前K个元素那就是答案,但是当数据非常多的时候,效率也会变得相对比较慢。

以上所述,直接排序对数据量很大的场景是不太合适的,所以我们利用优先级队列来解决TopK问题,我们设想一下,我们要找前K大的数据,这时候我们的优先级队列要实现一个大堆还是一个小堆?答案是小堆,当我们把题目要求K个元素放入堆中之后,就形成了一个小堆,我们之后只要第K+1个和堆顶进行比较,比堆顶大的就把堆顶弹出,把新的元素放入堆中,以此类推,最后你会发现堆顶的元素就是第K大的元素,因为他是一个小堆,所以堆顶以下的元素都比堆顶元素大,所以你只要把这个堆里面的值打印出来那就是前K大的元素了。

以上就是TopK问题的整体思路,我们上面以取前K大的元素为例,我们如果要取前K小的元素,就模仿上面所讲,建一个大堆来进行处理,就能得到答案。

我们用一个例子来理解TopK问题(Java来解决):

找出数组中最小的K个数。

arr = [1,3,10,5,9,8,2], K = 3

我们期望得到的结果是:[1,2,3]

我们要找到前K小个数,所以我们这里建立一个大堆:

因为PriorityQueue默认是一个小堆,这时候我们需要传入比较器进行建立大堆的操作。

PriorityQueue priorityQueue=new PriorityQueue<>(k,new Comparator(){

            public int compare(Integer o1,Integer o2){

                return o2-o1;

            }

        });

然后我们遍历整个数组,在优先级队列中放入K个元素,如果优先级队列中有了K个元素,我们就来比较堆顶元素和其他元素的大小关系。如果堆顶小,就先出队,再放入元素。

for(int i=0;i

            if(priorityQueue.size()

                priorityQueue.offer(arr[i]);

            }else{

                int top=priorityQueue.peek();

                if(top>arr[i]){

                    priorityQueue.poll();

                    priorityQueue.offer(arr[i]);

                }

            }

        }

最后我们只要输出一下优先级队列中的元素即可得到答案。

你可能感兴趣的:(算法)