有一个包含20亿个全是32位整数的大文件,在其中找到出现次数最多的数。
要求: 内存限制2GB。
初级进阶: 40亿个整数。
高级进阶: 80亿个整数。
常规思路:
在很多整数中找到出现次数最多的数,通常的做法是使用哈希表对出现的每一个数做词频统计。如果一个数字出现20亿次,哈希表的一条记录需要8B。如果20亿个数都不同,那么哈希表的20亿条记录需要16GB。
解决思路:
记录大概 2 亿多条不同的记录,2 亿多条不同的记录,大概1.6GB 的内存。我们可以把这 20 亿个数存放在不同的文件,然后再来筛选。例如,在 0 至 2 亿之间的放在文件1中,在 2 亿至 4 亿之间的放在文件2中….,由于 int 型整数大概有 42 亿个不同的数,所以我可以把他们映射到 21 个文件中去,如图:
显然,相同的数一定会在同一个文件中,我们这个时候就可以统计每个文件中出现次数最多的数,然后再从这些数中再次选出最多的数。
如果这 20 亿个数数值比较集中的话,怎么优化?
如果给的这 20 亿个数数值比较集中的话,可以先把每个数先做哈希函数映射,根据哈希函数得到的哈希值,再把他们存放到对应的文件中,如果哈希函数设计到好的话,那么这些数就会分布的比较平均。
初级进阶: 可以加大文件的数量(映射到42个文件)。
如果给的这 40 亿个数中数值都是一样的,那么哈希表中,某个 key 的 value
存放的数值就会是 40 亿,然而 int 的最大数值是 21 亿左右,那么就会出现溢出,该怎么办?
(把 int 改为 long 会占用更多的内存),可以把 value 初始值赋值为 负21亿,这样,如果 value 的数值是 21 亿的话,就代表某个 key 出现了 42 亿次了。
高级进阶:可以一边遍历一遍判断,如果在统计的过程中,发现某个 key 出现的次数超过了 40 亿次,那么,就不可能再有另外一个 key 出现的次数比它多了,那我直接把这个 key 返回就搞定了。
常规套路:把一个大的集合通过哈希函数分配到多台机器中,或者分配到多个文件里,但是到底分配多少台机器、分配到多少文件,在解题时一定要确定下来。
参考网站:网站链接