这是在网上找到的一道百度的面试题:
搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复度比较 高,虽然总数是1千万,但如果除去重复后,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。请你统计最热门的10个查询 串,要求使用的内存不能超过1G。
解答转自:http://blog.redfox66.com/post/2010/09/23/top-k-algoriyhm-analysis.aspx
问题解析:
【分析】:要统计最热门查询,首先就是要统计每个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,和算法而相比,又有了比较大的改进。
分享到:
相关推荐
标题中的“TOPK算法的Hash实现”指的是使用哈希数据结构来解决找出数据集中最大或最小的K个元素的问题。这种算法通常用于大数据处理和实时分析中,因为哈希表可以提供快速的查找和更新操作。 TOPK算法的核心是通过...
本篇文章主要探讨的是利用二分法实现Top K算法。 **一、二分法实现Top K算法** 1. **基本思想** 二分法实现的Top K算法的核心是通过不断地将数据集划分为两部分,每次保证一部分的大小不超过K,从而逐步缩小搜索...
"基于二分查找的有序表在做topK算法的给力实现" 这个标题揭示了我们将在JavaScript开发中探讨一种高效的算法实现,即如何利用有序表(通常是一个排序数组)和二分查找来执行topK算法。TopK算法的主要目标是从大量...
典型的Top K算法 找出一个数组里面前K个最大数 Top K算法是解决一个经典的问题,即在一个大规模的数组中找到前K个最大数的问题。在这个问题中,我们需要在一个数组中找到前K个最大数,例如在搜索引擎中,需要找出最...
Python中的TopK算法是一种在数据集中查找最大或最小K个元素的高效算法。在这个实例中,我们看到一个基于快速选择(Quick Select)的TopK实现,这是一个简化版的快速排序算法,专门用于寻找数组中的第K小(或大)的...
【标题】:“TOP K算法.pdf” 【描述】:该文档主要介绍了编程面试中常见的Top K算法问题,包括其实现和应用。文章由July、zhouzhenren和yansha共同编写,并提到了在2011年05月08日的更新。文档通过之前的寻找最小k...
在上述文档中,提到了三种不同的Top K算法实现: 1. **寻找最小的第 k 个数**: 这个实现使用了快速选择算法,它是快速排序的一个变体,但目标不是完全排序数组,而是找到第 k 小的元素。通过选择一个枢轴元素并...
1. **Top K问题**:Top K问题是指在一组数据中找出出现频率最高的K个元素,常用于数据分析、搜索引擎优化等领域。在这个面试题中,目标是找出最热门的10个查询字符串。 2. **排序算法**: - **直接排序法**:最...
Top K算法是一种在大量数据中找出出现频率最高的K个元素的高效算法。在这个问题中,我们需要在JavaScript中实现这个算法,以找出搜索引擎日志中最热门的10个查询字符串。首先,我们需要理解堆数据结构以及如何利用堆...
topk问题的Python实现,k-堆实现
这个“java实现TOP查询”的作业来自东北大学软件学院的java期末项目,旨在让学生掌握分布式TOPK算法的基本实现。这里我们将深入探讨相关知识点。 首先,让我们了解什么是TOP查询。在数据库或数据处理中,TOP查询...
根据给定的实验报告文件的信息,我们可以总结出以下关于算法设计与分析实验的相关知识点: ### 一、实验背景 本次实验属于深圳大学计算机与软件学院的《算法设计与分析》课程的一部分,旨在通过实践加深学生对几种...
Java实现TopK问题的方法是指在大量数据中找到TopK个最大或最小的元素, 这是一个常见的算法问题。下面将从两种方法来实现Java实现TopK问题:基于快排的TopK实现和堆排序实现TopK。 基于快排的TopK实现: 快排是最...
在描述的“百度面试题 Top K 算法”中,哈希表可以高效地解决这类问题。通过建立一个大小为K的最小堆,然后遍历数据,将每个元素与堆顶元素比较,如果小于堆顶则替换,并调整堆。同时,可以使用哈希表记录每个元素...
此外,ECHT算法还提升了Top-k算法的阈值计算精度,减少了网络带宽的消耗。ECHT算法引入了“早裁剪”技术,即在大量数据传输之前,提前进行数据的裁剪,从而避免了大量无用数据的传输。 该算法通过实验验证,相比于...