技巧:
题目一:范围统计搜索-位图
32位无符号整数的范围是0~4,294,967,295( 2 32 − 1 2^{32}-1 232−1)
现有一个正好包含40亿个无符号整数的文件,所以一定有没出现过的无符号整数
如何使用1GB内存找到没有出现的数?
【进阶】内存为3KB,找到一个没有出现的数
分析
没有硬盘空间,没办法用哈希分流做,用位图做
32位无符号整数个数为 2 32 2^{32} 232,占用空间为 2 32 / 8 2^{32}/8 232/8字节byte=500MB
所以对于原问题,申请一个大小500mb左右的int数就可以解决,出现过的数对应位置为1,则为0的位对应无符号数就是没出现过的
对于进阶问题,3KB可以容纳数组unsigned int[512] arr
,那么可以把
2
32
2^{32}
232个无符号整数等分为512份,每份
2
23
2^{23}
223个数
注意:每个unsigned int占用4Byte
那么数组arr[0]表示0~ 2 23 − 1 2^{23}-1 223−1这些数出现的总次数
arr[1]表示 2 23 2^{23} 223~ 2 24 − 1 2^{24}-1 224−1这些数出现的总次数
···············
以此类推
那么一定有某个arr[i]小于 2 23 2^{23} 223,那我就知道缺的数字来自哪个范围了
接下来在这个范围上继续划分为512份,继续统计词频,然后有知道了一个更小的范围
周而复始,一定可以找到一个缺少的数字
再进一步,使用有限几个变量解决
那么不断二分 2 32 2^{32} 232即可,其实就是把512换成2
32次二分就可以找到解
题目二
有一个包含100亿个URL的大文件,假设每个URL占用64B,找出其中所有重复的URL
1、hash分流
将所有url哈希取模后,放入不同的文件,统计每个文件的重复url
2、布隆过滤器
插入的过程中也查询,查询到已经插入过的url就记录在一个文件中(有失误率)
【补充】
某搜索公司一天的用户搜索词汇达到百亿数据量,设计一种求出每天热门top100词汇的可行办法
首先用hash函数分流成多个小文件,每个小文件的top100可以很容易的统计出来
下面讲使用堆来根据小文件的top100算出总的top100
每个小文件的url根据词频形成大根堆
下面把每个大根堆的堆顶单独拿出来,组织成一个总大根堆
弹出总大根堆的堆顶,找到他所属的小文件大根堆,pop小堆的堆顶,然后把新的小堆堆顶放入总大根堆
题目三
32位无符号整数的范围是0~4,294,967,295( 2 32 − 1 2^{32}-1 232−1)
现有一个正好包含40亿个无符号整数的文件,如何使用1GB内存找到所有出现了2次的数?
【进阶】内存为10MB,找到这40亿个数的中位数
万能解法:hash函数分流,将所有数分到若干小文件中去,再单独对小文件内容计数
位图:用2个位表示数出现的状态,00无意义,01表示出现0次,01表示出现1次,10表示出现2次,11就是出现多于2次
所以申请 2 32 ∗ 2 / 8 2^{32}*2/8 232∗2/8Byte= 2 30 2^{30} 230B=1GB大小的空间作为位图
【进阶】范围统计思想,10MB内存可以容纳unsigned int[ 2 20 2^{20} 220],将40亿个数分为 2 20 2^{20} 220份,每个arr[i]就存放了第i份数出现的频数,那么找到第20亿个数出现的范围,再继续划分小范围,最终就可以定位到中位数所在的很小范围内
题目四:腾讯原题
10GB的文件内存储了无序的int数据,如何利用5GB内存空间,对数据进行排序,生成一个有序的文件?
使用堆!
一个小根堆,内容存放数据本身和它的词频(共8Byte),根据数据本身排序
堆中还有一些索引信息,所以把一条记录看成16Byte
5GB内存可存放的记录数量为5GB/16B=
5
∗
2
26
>
2
28
5*2^{26}>2^{28}
5∗226>228
int的大小为
−
2
31
2
31
−
1
-2^{31}~2^{31}-1
−231 231−1
2
32
2^{32}
232个数等分为
2
28
2^{28}
228份,每份范围是
2
4
2^4
24
小根堆先统计最低范围上的数字的词频
统计完以后,按照这些数出现的次数输出到一个文件中去
然后继续下一个范围的统计,再输出
······
最终统计完所有小范围的数,也全部输出了,排序就结束了
还有另一种思路,不使用范围,而是每次统计最小的几个数的词频,并且用一个阈值来限制本次统计的词的最小值(也就是已经统计完的词的最大值)