者:码农面试
问题描述:算法
这是在网上找到的一道百度的面试题:数组
搜索引擎会经过日志文件把用户每次检索使用的全部检索串都记录下来,每一个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复度比较 高,虽然总数是1千万,但若是除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。请你统计最热门的10个查询 串,要求使用的内存不能超过1G。数据结构
问题解析:优化
【分析】:要统计最热门查询,首先就是要统计每一个Query出现的次数,而后根据统计结果,找出Top 10。因此咱们能够基于这个思路分两步来设计该算法。下面分别给出这两步的算法:搜索引擎
第一步:Query统计设计
算法一:直接排序法日志
首先咱们能想到的算法就是排序了,首先对这个日志里面的全部Query都进行排序,而后再遍历排好序的Query,统计每一个Query出现的次数了。但 是题目中有明确要求,那就是内存不能超过1G,一千万条记录,每条记录是225Byte,很显然要占据2.55G内存,这个条件就不知足要求了。排序
让咱们回忆一下数据结构课程上的内容,当数据量比较大并且内存没法装下的时候,咱们能够采用外排序的方法来进行排序,这里笔者采用归并排序,是由于归并排序有一个比较好的时间复杂度O(NlgN)。索引
排完序以后咱们再对已经有序的Query文件进行遍历,统计每一个Query出现的次数,再次写入文件中。
综合分析一下,排序的时间复杂度是O(NlgN),而遍历的时间复杂度是O(N),所以该算法的整体时间复杂度就是O(NlgN)。
算法二:Hash Table法
在上个方法中,咱们采用了排序的办法来统计每一个Query出现的次数,时间复杂度是NlgN,那么能不能有更好的方法来存储,而时间复杂度更低呢?
题目中说明了,虽然有一千万个Query,可是因为重复度比较高,所以事实上只有300万的Query,每一个Query255Byte,所以咱们能够考虑 把他们都放进内存中去,而如今只是须要一个合适的数据结构,在这里,Hash Table绝对是咱们优先的选择,由于Hash Table的查询速度很是的快,几乎是O(1)的时间复杂度。
那么,咱们的算法就有了:维护一个Key为Query字串,Value为该Query出现次数的HashTable,每次读取一个Query,若是该字串 不在Table中,那么加入该字串,而且将Value值设为1;若是该字串在Table中,那么将该字串的计数加一便可。最终咱们在O(N)的时间复杂度 内完成了对该海量数据的处理。
本方法相比算法一:在时间复杂度上提升了一个数量级,但不单单是时间复杂度上的优化,该方法只须要IO数据文件一次,而算法一的IO次数较多的,所以该算法比算法一在工程上有更好的可操做性。
第二步:找出Top 10
算法一:排序
我想对于排序算法你们都已经不陌生了,这里不在赘述,咱们要注意的是排序算法的时间复杂度是NlgN,在本题目中,三百万条记录,用1G内存是能够存下的。
算法二:部分排序
题目要求是求出Top 10,所以咱们没有必要对全部的Query都进行排序,咱们只须要维护一个10个大小的数组,初始化放入10Query,按照每一个Query的统计次数由 大到小排序,而后遍历这300万条记录,每读一条记录就和数组最后一个Query对比,若是小于这个Query,那么继续遍历,不然,将数组中最后一条数 据淘汰,加入当前的Query。最后当全部的数据都遍历完毕以后,那么这个数组中的10个Query即是咱们要找的Top10了。
不难分析出,这样的算法的时间复杂度是N*K, 其中K是指top多少。
算法三:堆
在算法二中,咱们已经将时间复杂度由
NlogN优化到NK,不得不说这是一个比较大的改进了,但是有没有更好的办法呢?
分析一下,在算法二中,每次比较完成以后,须要的操做复杂度都是K,由于要把元素插入到一个线性表之中,并且采用的是顺序比较。这里咱们注意一下,该数组 是有序的,一次咱们每次查找的时候能够采用二分的方法查找,这样操做的复杂度就降到了logK,但是,随之而来的问题就是数据移动,由于移动数据次数增多 了。不过,这个算法仍是比算法二有了改进。
基于以上的分析,咱们想一想,有没有一种既能快速查找,又能快速移动元素的数据结构呢?回答是确定的,那就是堆。
借助堆结构,咱们能够在log量级的时间内查找和调整/移动。所以到这里,咱们的算法能够改进为这样,维护一个K(该题目中是10)大小的小根堆,而后遍历300万的Query,分别和根元素进行对比。。。
那么这样,这个算法发时间复杂度就降到了NlogK,和算法而相比,又有了比较大的改进。
结语:
至此,咱们的算法就彻底结束了,通过步骤一和步骤二的最优结合,咱们最终的时间复杂度是O(N) + O(N')logK。若是各位有什么好的算法,欢迎跟帖讨论。