TopK-在海量数据中找出前K个最值的问题
对于此类问题,我们一般想到的算法是排序算法,首先给数据进行排序,再去获取k个最值
但是当问题的规模内存中放不下时,普通的内排序就无法进行。对于海量数据的topk问题,一种常用的做法是借助堆解决。
如果需要获取最大的k个值,可以建小堆
首先读入前k个数据存入一个最小堆
然后遍历后续的数据,对于每一个遍历的数据,都和堆顶(k个数据中最小的)数据比较
如果比堆顶数据小,则继续遍历后续数据
如果比堆顶数据大,则删除堆顶元素,存入当前遍历到的数据
整个过程直到所有数据遍历完为止
时间复杂度
如果数据量为n,找到topK个元素,则每次堆的插入和删除时间复杂度为logk。
最坏情况下,对于每一个元素都要进行堆的插入和删除,则最坏时间复杂度为O(nlogk)
最好情况下,前k个元素即为topK个元素,堆不需要进行调整,则最好时间复杂度为O(n)
空间复杂度
需要一个大小为k的堆保存topK个元素,故空间复杂度为O(k)
priority_queue<int>topk(vector<int>nums, int k){
priority_queue<int>mmq;
for (int num : nums){
if (mmq.size() < k || mmq.top()<num){
mmq.push(num);
}
if (mmq.size()>k){
mmq.pop();
}
return mmq;
}
}
vector<int>findtopk(vector<int>&nums, int k){
priority_queue<int>mq = topk(nums, k);
vector<int>v;
while (!mq.empty()){
v.push_back(mq.top());
mq.pop();
}
return v;
}
topK的场景
有海量个查询字符串记录,统计最热门的K个查询串
从一个大文件中找出频数最高的K个词
找出某日访问网站次数最多的K个IP
只要涉及到从数据中找出k个最值的问题都属于topK问题