Android面试Hash算法题


Hash部分分为三部分讲解,各位游客可根据分类进行对应博客阅读:

  1. 开发面试Hash原理详解
  2. 开发面试Hash常见算法
  3. 开发面试Hash面试考题

博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !

1. Hash Top 查找

内容描述

1)搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。
2)假设目前有一千万个记录(这些查询串的重复度比较高,虽然总数是1千万,但如果除去重复后,不超过3百万个。
2)一个查询串的重复度越高,说明查询它的用户越多,也就是越热门。

要求

请你统计最热门的10个查询串,要求使用的内存不能超过1G。

分析

有两种思路:使用排序的方案 和 使用hash的方法

1.排序法
1) 首先我们最先想到的的算法就是排序了,首先对这个日志里面的所有Query都进行排序,然后再遍历排好序的Query,统计每个Query出现的次数了。

2)但是题目中有明确要求,那就是内存不能超过1G,一千万条记录,每条记录是255Byte,根据255100010000/(102410241024)=2.37G大小的内存

3)当数据量比较大而且内存无法装下的时候,我们可以采用外排序的方法来进行排序,这里我们可以采用归并排序,归并排序有一个比较好的时间复杂度O(nlogn)

4)排完序之后我们再对已经有序的Query文件进行遍历,统计每个Query出现的次数,再次写入文件中,其时间复杂度O(n)。

5)总体时间复杂度O(n)+O(nlogn)=O(nlogn)

2.Hash Table法
对于数据的统计相比排序有更好的方案,那就是使用hash table的方式。

题目中虽然有一千万个Query,但是由于重复度比较高,因此事实上只有300万的Query量,其大小为2.37*0.3=0.71G,对于1G的内存要求是满足的。Hash Table的查找速度非常快接近O(1)。

这样我们的算法就是:维护一个Key为Query字串,Value为该Query出现次数的HashTable,每次读取一个Query,如果该字串不在Table中,那么加入该字串,并且将Value值设为1;如果该字串在Table中,那么将该字串的计数加一即可。最终我们在O(n)的时间复杂度内完成了对该海量数据的处理。

比较:Hash Table相对于排序法在时间复杂度上提高了一个数量级,为O(n)。且hash Table的方案只需要进行一次IO数据操作,在操作性上更有优势

补充

算法:部分排序
题目要求是求出Top 10,因此我们没有必要对所有的Query都进行排序,我们只需要维护一个10个大小的数组,初始化放入10个Query,按照每个Query的统计次数由大到小排序,然后遍历这300万条记录,每读一条记录就和数组最后一个Query对比,如果小于这个Query,那么继续遍历,否则,将数组中最后一条数据淘汰,加入当前的Query。

最后当所有的数据都遍历完毕之后,那么这个数组中的10个Query便是我们要找的Top10了。不难分析出,这样,算法的最坏时间复杂度是N*K, 其中K是指top多少。

算法:堆
在部分算法二中,每次比较完成之后,需要的操作复杂度都是K,因为要把元素插入到一个线性表之中,而且采用的是顺序比较。

这里我们注意一下,该数组是有序的,一次我们每次查找的时候可以采用二分的方法查找,这样操作的复杂度就降到了logK,可是,随之而来的问题就是数据移动,因为移动数据次数增多了。不过,这个算法还是比算法二有了改进。

基于以上的分析,我们想到一种既能快速查找,又能快速移动元素的数据结构呢?回答是肯定的,那就是堆。
借助堆结构,我们可以在log量级的时间内查找和调整/移动。因此到这里,我们的算法可以改进为这样,维护一个K(该题目中是10)大小的小根堆,然后遍历300万的Query,分别和根元素进行对比。

与部分算法相比我们采用了最小堆这种数据结构代替数组,把查找目标元素的时间复杂度有O(K)降到了O(logK)。采用堆数据结构,最终的时间复杂度就降到了N‘logK。

总结

最优的方案是先用Hash表统计每个Query出现的次数O(N),然后用堆数据结构找出前10,时间复杂度为N*O(logK),所以总的时间复杂度是O(N)+NO(logK)。 N=1000万 ,N=300万

2. SimHash应用

内容描述

如何设计一个比较两篇文章相似度的算法?

要求

用最快最有效的方式比较两篇文章的相似度。

分析

我们首选最容易想到的两种方案是

  1. 一种方案是先将两篇文章分别进行分词,得到一系列特征向量,然后计算特征向量之间的距离(可以计算它们之间的欧氏距离、海明距离或者夹角余弦等等),从而通过距离的大小来判断两篇文章的相似度。
  2. 另外一种方案是传统hash,我们考虑为每一个web文档通过hash的方式生成一个指纹(finger print)。

比较两种法案
+采取第一种方法,若是只比较两篇文章的相似性还好,但如果是海量数据呢,有着数以百万甚至亿万的网页,要求你计算这些网页的相似度。你还会去计算任意两个网页之间的距离或夹角余弦么?想必你不会了。

+第二种方案中所说的传统加密方式md5,其设计的目的是为了让整个分布尽可能地均匀,但如果输入内容一旦出现哪怕轻微的变化,hash值就会发生很大的变化。如果只改变一个文字其Hash值差别都很大不容易进行比较。
H^md5(“the cat sat on the mat”)=415542861
H^md5(“the cat sat on the mat”)=668720516

可理想当中的hash函数,需要对几乎相同的输入内容,产生相同或者相近的hash值,换言之,hash值的相似程度要能直接反映输入内容的相似程度,故md5等传统hash方法也无法满足我们的需求。

来自于GoogleMoses Charikar发表的一篇论文“detecting near-duplicates for web crawling”中提出了simhash算法,专门用来解决亿万级别的网页的去重任务。
具体使用极其原理请查看我的博客《开发面试Hash常见算法》

总结

使用Simhash能完美快速的解决网页去重判断处理。

博客书写不易,您的点赞收藏是我前进的动力,千万别忘记点赞、 收藏 ^ _ ^ !

相关链接

  1. 开发面试Hash原理详解
  2. 开发面试Hash常见算法
  3. ART与Dalvik、JVM之间的关系你懂了吗?
  4. 热更新你都知道哪些?

猜你喜欢

转载自blog.csdn.net/luo_boke/article/details/106693341
今日推荐