题目:
CVTE笔试题https://www.1024do.com/?p=3949
搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。
假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。),请你统计最热门的10个查询串,要求使用的内存不能超过1G。
 
思路:此题解题步骤可分为两步:1.统计每个“查询串”(下称为query)出现的次数  2.根据统计结果,找出top 10
 
1.统计query出现次数:
利用hash思想,维护一个Key为Query字串,Value为该Query出现次数的HashTable。每次读取一个Query,如果该字串不在Table中,那么加入该字串,并且将Value值设为1;如果该字串在Table中,那么将该字串的计数加一即可。
因为hashtable中查询速度非常快,几乎达到O(1)的时间复杂度,所以统计N个记录,时间复杂度能达到O(N),线性的时间复杂度
 
2.根据统计结果,找出topK
借助堆结构,我们可以在log量级的时间内查找和调整/移动。‘
具体做法:维护一个K(该题目中是10)大小的小根堆,然后遍历300万的Query,分别和根元素进行对比。(这道题目因为是找“最大”的10个,所以用小根堆,每次遍历的元素只要和堆中最小的元素——“根”作比较,如果小于根,说明肯定进不了topK;如果大于根,说明它可以淘汰堆中的最小的一个元素,也就是根,然后再调整)
 
堆中最后剩下的K个元素就是top K
 
TOP   K问题

Top k问题的讨论(三种方法的java实现及适用范围)

在很多的笔试和面试中,喜欢考察Top K.下面从自身的经验给出三种实现方式及实用范围。

  1. 合并法

这种方法适用于几个数组有序的情况,来求Top k。时间复杂度为O(k*m)。(m:为数组的个数).具体实现如下:

/**
* 已知几个递减有序的m个数组,求这几个数据前k大的数
*适合采用Merge的方法,时间复杂度(O(k*m);
*/
import java.util.List;
import java.util.Arrays;
import java.util.ArrayList;
public class TopKByMerge{
public int[] getTopK(List<List<Integer>>input,int k){
int index[]=new int[input.size()];//保存每个数组下标扫描的位置;
int result[]=new int[k];
for(int i=0;i<k;i++){
int max=Integer.MIN_VALUE;
int maxIndex=0;
for(int j=0;j<input.size();j++){
if(index[j]<input.get(j).size()){
if(max<input.get(j).get(index[j])){
max=input.get(j).get(index[j]);
maxIndex=j;
}
}
}
if(max==Integer.MIN_VALUE){
return result;
}
result[i]=max;
index[maxIndex]+=1; }
return result;
}
  1.  快排过程法

快排过程法利用快速排序的过程来求Top k.平均时间复杂度为(O(n)).适用于无序单个数组。具体java实现如下:

Quick Select的目标是找出第k大元素,所以

选取一个基准元素pivot,将数组切分(partition)为两个子数组,

  • 若切分后的左子数组的长度 > k,则第k大元素必出现在左子数组中;
  • 若切分后的左子数组的长度 = k-1,则第k大元素为pivot;
  • 若上述两个条件均不满足,则第k大元素必出现在右子数组中。
/*
*利用快速排序的过程来求最小的k个数
*
*/
public class TopK{
int partion(int a[],int first,int end){
int i=first;
int main=a[end];
for(int j=first;j<end;j++){
if(a[j]<main){
int temp=a[j];
a[j]=a[i];
a[i]=temp;
i++;
}
}
a[end]=a[i];
a[i]=main;
return i;
}
void getTopKMinBySort(int a[],int first,int end,int k){
if(first<end){
int partionIndex=partion(a,first,end);
if(partionIndex==k-1)return;
else if(partionIndex>k-1)getTopKMinBySort(a,first,partionIndex-1,k);
else getTopKMinBySort(a,partionIndex+1,end,k);
}
}
public static void main(String []args){
int a[]={2,20,3,7,9,1,17,18,0,4};
int k=6;
new TopK().getTopKMinBySort(a,0,a.length-1,k);
for(int i=0;i<k;i++){
System.out.print(a[i]+" ");
}
}
}
  1. 采用小根堆或者大根堆

求最大K个采用小根堆,而求最小K个采用大根堆。

求最大K个的步奏:

  1. 根据数据前K个建立K个节点的小根堆。
  2. 在后面的N-K的数据的扫描中,
  • 如果数据大于小根堆的根节点,则根节点的值覆为该数据,并调节节点至小根堆。
  • 如果数据小于或等于小根堆的根节点,小根堆无变化。

求最小K个跟这求最大K个类似。时间复杂度O(nlogK)(n:数据的长度),特别适用于大数据的求Top K。

/**
* 求前面的最大K个 解决方案:小根堆 (数据量比较大(特别是大到内存不可以容纳)时,偏向于采用堆)
*
*
*/
public class TopK {
/**
* 创建k个节点的小根堆
*
* @param a
* @param k
* @return
*/
int[] createHeap(int a[], int k) {
int[] result = new int[k];
for (int i = 0; i < k; i++) {
result[i] = a[i];
}
for (int i = 1; i < k; i++) {
int child = i;
int parent = (i - 1) / 2;
int temp = a[i];
while (parent >= 0 &&child!=0&& result[parent] >temp) {
result[child] = result[parent];
child = parent;
parent = (parent - 1) / 2;
}
result[child] = temp;
}
return result; } void insert(int a[], int value) {
a[0]=value;
int parent=0; while(parent<a.length){
int lchild=2*parent+1;
int rchild=2*parent+2;
int minIndex=parent;
if(lchild<a.length&&a[parent]>a[lchild]){
minIndex=lchild;
}
if(rchild<a.length&&a[minIndex]>a[rchild]){
minIndex=rchild;
}
if(minIndex==parent){
break;
}else{
int temp=a[parent];
a[parent]=a[minIndex];
a[minIndex]=temp;
parent=minIndex;
}
} } int[] getTopKByHeap(int input[], int k) {
int heap[] = this.createHeap(input, k);
for(int i=k;i<input.length;i++){
if(input[i]>heap[0]){
this.insert(heap, input[i]);
} }
return heap; } public static void main(String[] args) {
int a[] = { 4, 3, 5, 1, 2,8,9,10};
int result[] = new TopK().getTopKByHeap(a, 3);
for (int temp : result) {
System.out.println(temp);
}
}
}

海量数据处理之top K问题的更多相关文章

  1. 海量数据处理的 Top K 相关问题

    Top-k的最小堆解决方法 问题描述:有N(N>>10000)个整数,求出其中的前K个最大的数.(称作Top k或者Top 10) 问题分析:由于(1)输入的大量数据:(2)只要前K个,对 ...

  2. 海量数据处理 - 10亿个数中找出最大的10000个数(top K问题)

    前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望能完成最后一面,各方面原因造成我无比想去鹅场的心已经按捺不住了),这个问题还是建立最小堆比较好一些. 先拿10000个数建堆, ...

  3. july教你如何迅速秒杀掉:99%的海量数据处理面试题

    作者:July出处:结构之法算法之道blog 以下是原博客链接网址 http://blog.csdn.net/v_july_v/article/details/7382693 微软面试100题系列 h ...

  4. 程序员编程艺术:第三章续、Top K算法问题的实现

    程序员编程艺术:第三章续.Top K算法问题的实现 作者:July,zhouzhenren,yansha.     致谢:微软100题实现组,狂想曲创作组.     时间:2011年05月08日    ...

  5. 如何解决海量数据的Top K问题

    1. 问题描述 在大规模数据处理中,常遇到的一类问题是,在海量数据中找出出现频率最高的前K个数,或者从海量数据中找出最大的前K个数,这类问题通常称为“top K”问题,如:在搜索引擎中,统计搜索最热门 ...

  6. (面试)Hash表算法十道海量数据处理面试题

    Hash表算法处理海量数据处理面试题 主要针对遇到的海量数据处理问题进行分析,参考互联网上的面试题及相关处理方法,归纳为三种问题 (1)数据量大,内存小情况处理方式(分而治之+Hash映射) (2)判 ...

  7. 海量数据处理面试题学习zz

    来吧骚年,看看海量数据处理方面的面试题吧. 原文:(Link, 其实引自这里 Link, 而这个又是 Link 的总结) 另外还有一个系列,挺好的:http://blog.csdn.net/v_jul ...

  8. 海量数据处理算法—Bloom Filter

    海量数据处理算法—Bloom Filter 1. Bloom-Filter算法简介 Bloom-Filter,即布隆过滤器,1970年由Bloom中提出.它可以用于检索一个元素是否在一个集合中. Bl ...

  9. 经典面试问题: Top K 之 ---- 海量数据找出现次数最多或,不重复的。

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

随机推荐

  1. mysql查看当前执行线程_关闭当前的某些线程 show processlist_kill

    每个与mysqld的连接都在一个独立的线程里运行,您可以使用SHOW PROCESSLIST语句查看哪些线程正在运行,并使用KILL thread_id语句终止一个线程. 如果您拥有SUPER权限,您 ...

  2. SV class

    SV中的class通过new来创建实例,new函数可以传递多个参数: packet P1:  P1 = new:创建一个P1的对象: P2 = P1:P2也指向同一个对象: P2 = new P1:P ...

  3. Kubernetes持久化存储1——示例

    目录贴:Kubernetes学习系列 一.简介 存储管理与计算管理是两个不同的问题.Persistent Volume子系统,对存储的供应和使用做了抽象,以API形式提供给管理员和用户使用.要完成这一 ...

  4. .net基本面试题

    OOP: Object Oriented Programming: 面向对象编程技术的关键性观念是它将数据及对数据的操作行为放在一起,作为一个相互依存.不可分割的整体——对象.对于相同类型的对象进行分 ...

  5. Dockerfile的HEALTHCHECK指令

    容器实例的状态虽然是up,但不能保证里面的进程一定是监控的.我门可以借助HEALTHCHECK指令来做监控状态检查 HEALTHCHECK指令有两种形式: HEALTHCHECK [OPTIONS] ...

  6. Html fieldset、legend 标签

    Html fieldset.legend 标签 <html> <body> <!-- fieldset 添加圈起标题框标签 --> <fieldset> ...

  7. Python 进程间数据交互

    进程间通信:进程之间必须需要中间件. 不同进程间内存是不共享的,要想实现两个进程间的数据交换     Queues:实现传输两个进程的数据 线程queue,访问数据只能在一个进程内进行线程与线程之间的 ...

  8. 3. Dubbo原理解析-Dubbo内核实现之动态编译 (转)

    转载自  斩秋的专栏  http://blog.csdn.net/quhongwei_zhanqiu/article/details/41577159 我们运行的Java代码,一般都是编译之后的字节码 ...

  9. 论文笔记:A Structured Self-Attentive Sentence Embedding

    A Structured Self-Attentive Sentence Embedding ICLR 2017 2018-08-19 14:07:29 Paper:https://arxiv.org ...

  10. Learning-Python【11】:函数嵌套及作用域

    一.函数对象 函数是第一类对象:函数的内存地址(即函数名)可以像一个变量值一样去使用 1.变量值可以被引用,例如 x = 1,y = x def foo(): print('from foo') f ...