参考链接
- 哈希函数可以把数据按照种类均匀分流
- 布隆过滤器用于集合的建立与查询,并可以节省大量空间
- 一致性hash解决数据服务器的负载管理问题
- 利用并查集结构做岛问题的并行计算、
- 位图解决某一范围上数字的出现情况,并可以节省大量空间
- 利用分段统计思想、并进一步节省空间
- 利用堆、外排序来做多个处理单元的结果合并
2GB内存,在20亿个整数中找到出现次数最多的数
hash分流+hash词频统计
用哈希表对出现的每一个数做词频统计,哈希表的key是某一个数,value是这个数出现的次数。
计数排序
在一定范围内,参照计数排序,将数字值作为数组的下标,出现次数作为数组的值。
40亿个整数
hash分流+hash词频统计
40亿的级别,词频统计时,以-2^31为初始值,最大出现次数40亿级可以存放。
80亿个整数
hash分流+hash词频统计
80亿的级别,词频统计时,一边遍历一遍判断,如果在统计的过程中,发现某个 key 出现的次数超过了 40 亿次,直接把这个 key 返回
32位无符号整数的范围是0~4,294,967,295,现在有一个正好包含40亿个无符号整数的文件,所以在整个范围中必然存在没出现过的数。可以使用最多1GB的内存,怎么找到所有未出现过的数?
位图
该题无符号整数的范围为0 到 2^32-1,无符号整数的个数为40亿个。
想要将范围上的所有数字存储在 bit 数组上。所需的数组长度是2^32,需要的内存为232/8(Byte)约等于512M左右,遍历该文件将出现的数所对应的bit 位变成1,剩下为0的位置对应的数就是没有出现过的数。
内存限制为3KB,但是只用找到一个没出现过的数即可
无符号整型数组 + 范围统计
3KB可以生成无符号整型数组为 3*1024/4=768。找到一个最接近这个数的2的某次方,即512.生成长度为512整型数组arr,该数组的每一个索引代表一个范围,范围长度为 2^32/512 = 2^23=8388608。例如,0代表0
~
8388607,1代表8388608~
16777215,…。遍历该文件将每个数出现在对应数组索引范围的数量++,即该范围的词频++,例如有一个数9,9除以8388608 = 0 所以arr[0]++。找到词频出现最少的范围再分成512份继续,最后总能找到一个没有出现的数。
使用有限几个变量,但是只用找到一个没出现过的数即可
二分法
将 2^32 二分,遍历文件 使用变量统计词频,将少于2^32/2的范围再次二分,依次循环总能找到一个未出现的数
32位无符号整数的范围是0~4294967295,现在有40亿个无符号整数,可以使用最多1GB的内存,找出所有出现了两次的数。
hash分流+hash词频统计
使用HashTable做词频统计器,一条记录8Byte = key(4字节)+value(4字节),1GB可以存储102410241024/8 = 227条记录。那么40亿条记录要使用Hash分流为4000000000/227约等于30个小文件,在每个小文件中找到出现两次的数即可。
位图
使用两个bit位来表示数量 00代表出现过0次 01代表出现过一次 10代表出现过2次 11代表出现过>2次
总共需要2^32*2bit位 1GB的内存可以实现。
可以使用最多10KB的内存,怎么找到这40亿个整数的中位数?
无符号整型数组 + 范围统计
3KB可以生成无符号整型数组为 3*1024/4=768。找到一个最接近这个数的2的某次方,即512.生成长度为512整型数组arr,该数组的每一个索引代表一个范围,范围长度为 2^32/512 = 2^23=8388608。例如,0代表0
~
8388607,1代表8388608~
16777215,…。遍历该文件将每个数出现在对应数组索引范围的数量++,即该范围的词频++,例如有一个数9,9除以8388608 = 0 所以arr[0]++。从arr[0]开始加,一直加到20亿就可以知道中位数出现在哪一个范围中,将这个范围再分512份,不断缩小范围,最后找到中位数
有一个包含100亿个URL的大文件,假设每个URL占用64B,请找出其中所有重复的URL
hash分流+hash词频统计
使用布隆过滤器(有失误率,源于hash冲突)
如果使用布隆过滤器的话,100亿个数据也就是需要100亿长度的bit数组,该数组的大小10000000000/8/1024/1024/1024 大概是1GB多 。遍历文件,每个数据记录hash值取模数组长度,如果当前bit位已经是1,说明重复,记录下来。
注意:bit数组的长度是根据内存限制条件来的,如果内存大一点的话就可以整的长一点,避免布隆过滤器的失误概率。要是内存足够大完全可以使用词频统计器了(精准寻找)。
使用hash函数分流(有失误率,源于hash冲突)
计算100亿个数据的hash值并使用1000取模,将这些数据分为1000块,由于hash函数的性质重复的URL一定会分到同一块中,再在每个块中求重复即可。
某搜索公司一天的用户搜索词汇是海量的(百亿数据量),请设计一种求出每天热门Top100词汇的可行办法
hash分流+hash词频统计+堆
先使用hash分流到 n个小文件中。使用hashTable记录每个小文件的词频并根据词频组成大根堆。维护一个包含n个小文件堆顶的总堆。总堆出一个,对应小文件减少一个,将该文件第二大的加入总堆
现在有一个100亿条url的黑名单记录,每条 url 平均 64 字节。此时随便输入一个 url,你如何快速判断该 url 是否在这个黑名单中
位图
优点:空间不随集合内元素个数的增加而增加。它的存储空间计算方式是找到所有元素里面最大的元素(假设为 N ),因此所占空间为(N/8)Byte,位图中每个位置只占1个bit。
缺点:空间复杂度随集合内最大元素增大而线性增大。
布隆过滤器
2GB内存,对20亿个整数进行排序
hash分流+数组排序
一个int数占4个字节,20亿个需要80亿字节,大概占用8GB的内存,而计算机只有2GB的内存,可以分为4个小文件,内排序后合并
hash分流+hash词频统计+堆
使用HashTable做词频统计器,一条记录8Byte = key(4字节)+value(4字节),2GB可以存储2^1024 ^1024*1024/16= 2^26条记录(除以16是因为HashTable索引的维护还需要一定空间给足,也可以除以100,200,只要比8大就行),有符号整数的范围是 -2^31 ~ 2^31-1 ,因此可以将整个范围分为2^(32) /2^(26) = 64块。从最小的范围开始使用HashTable做词频统计器并维护一个小根堆并依次输出,把总的文件过24遍就能完成(每次只关注一个范围上的数)
计数排序
解决方法 | 场景 |
---|---|
hash分流+hash词频统计+堆(排行榜) | 排序、Topk |
hash分流+hash词频统计(出现次数) | 出现最多、重复 |
hash分流 | 所有 |
计数排序(排序) | 出现最多、topk |
位图(存在情况) | 未出现、重复 |
布隆过滤器(判断存在) | 重复 |