面试题-10亿个数中找出最大的10000个数(top K问题)
一个较好的方法:先拿出10000个建立小根堆,对于剩下的元素,如果大于堆顶元素的值,删除堆顶元素,再进行插入操作,否则直接跳过,这样知道所有元素遍历完,堆中的10000个就是最大的10000个。时间复杂度: m + (n-1)logm = O(nlogm)
优化的方法:可以把所有10亿个数据分组存放,比如分别放在1000个文件中(如果是字符串hash(x)%M)。对每个文件,建立大小为10000的小根堆,然后按有序数组的合并合并起来,取出最大的10000个即是答案。
top K问题
在大规模数据处理中,经常会遇到的一类问题:在海量数据中找出出现频率最好的前k个数,或者从海量数据中找出最大的前k个数,这类问题通常被称为top K问题。例如,在搜索引擎中,统计搜索最热门的10个查询词;在歌曲库中统计下载最高的前10首歌等。
解决方法:针对top K类问题,通常比较好的方案是分治+Trie树/hash+小顶堆(就是上面提到的最小堆),即先将数据集按照Hash方法分解成多个小数据集,然后使用Trie树或者Hash统计每个小数据集中的query词频或频数,之后用小顶堆求出每个数据集中出现频率最高的前K个数,最后在所有top K中求出最终的top K。
简陋的实现:
估计能处理1e8个整数(约400M)吧
#include<bits/stdc++.h> using namespace std; int n, k, tmp; priority_queue<int, vector<int>, greater<int>>qu; int main() { scanf("%d%d", &n, &k); for(int i = 0;i < k;i++) { scanf("%d", &tmp); qu.push(tmp); } for(int i = 0;i < n-k;i++) { scanf("%d", &tmp); if(tmp > qu.top()) { qu.pop(); qu.push(tmp); } } for(int i = 0;i < k;i++) { printf("%d ", qu.top()); qu.pop(); } return 0; }
参考链接:
个性签名:时间会解决一切