题目:
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. Oracle中如何使用REGEXP_SUBSTR函数动态截取字符串

    REGEXP_SUBSTR函数格式如下: function REGEXP_SUBSTR(String, pattern, position, occurrence, modifier)__srcstr ...

  2. 笔记-ASP.NET WebApi

    本文是针对ASP.NET WepApi 2 的笔记. Web API 可返回的结果: 1.void 2.HttpResponseMessage 3.IHttpActionResult 4.其他类型 返 ...

  3. 关闭jtag保留swd

    串行线JTAG 配置 (Serial wire JTAG configuration)  位26:24  这些位只能由软件写( 读这些位,将返回未定义的数值) ,用于配置SWJ和跟踪复用功能的I/O ...

  4. MSG结构体和WndProc窗口过程详解

    MSG结构体和WndProc窗口过程对于Windows编程非常重要,如果不了解它们,可以说就没有学会Windows编程. MSG结构体 MSG 结构体用来表示一条消息,各个字段的含义如下: typed ...

  5. function的toString方法

    javascript的创建多行字符串的除了平时常见的”“+ 反斜杠\ 还有ES6的` ` 在js51上发现一个很有意思的方法 function heredoc(fn) { return fn.toSt ...

  6. 一些sql优化原则

    1.我们在设计表的时候,尽量让字段拥有默认值,尽量不要让字段的值为null. 因为,在 where 子句中对字段进行 null 值判断(is null或is not null)将导致引擎放弃使用索引而 ...

  7. Shiro权限管理框架

    一.Shiro介绍 Apache Shiro 是Java 的一个安全框架.Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在JavaSE 环境,也可以用在JavaEE 环境.Shiro 可以 ...

  8. Shell 实践、常用脚本进阶

    1.备份单个文件 #!/bin/bash #备份单个文件 DATE=`/bin/date +%y%m%d` /bin/tar -czpf /backup/$1.$DATE.tar.gz /backup ...

  9. Bugku-CTF之变量1

    Day9 变量1 http://123.206.87.240:8004/index1.php      

  10. Ansible在Ubuntu上的安装

    #apt安装 apt-get install software-properties-common apt-add-repository ppa:ansible/ansible apt-get upd ...