算法通关村第15关【白银】| 海量数据场景下的热门算法题

1. 从40个亿中产生一个不存在的整数

题目要求: 给定一个输入文件,包含40亿个非负整数,请设计一个算法,产生一个不存在该文件中的整数,假设你有1GB的内存来完成这项任务
进阶: 如果只有10MB的内存可用,该怎么办?

1)使用位图存储大数据

这个基础原理可以看位图基础位存储的核心就是存储一个数的位置而不是它本身

如果用哈希表来存40亿个数,最坏的情况下40亿个数字都不相同也就是需要40亿*4B的空间,大概是15GB大于所给空间了,这里使用位图来存储数字的位置,可以直接每个数字缩小4B,那就是40亿*1bit空间=500兆。

遍历一遍将碰到的数字对应的位置置为1,再遍历一边找出没被设为1的数

2)使用10MB来存储

这个时候就要用到海量数据的常用处理思路:分批分块处理

我们只有10MB空间,就算用位图来存储也只能存83886080个数字

题目只有一个不存在的数字,并且是非负整数那么大小就在0-2^32-1(4294967295)的范围内可以进行平分为64个区间,每个区间包含67,108,864个数,使用一个长度为64的整型数组 countArr 统计每个区间上的数的数量。如果一个区间上的计数小于67,108,864,说明至少有一个数在该区间内没有出现。

第二次遍历:对于计数小于67,108,864的区间,选择其中一个区间,例如第37区间。为这个区间的所有数构建一个位图 bitArr,大小约为8MB(67,108,864个位,每个位用1或0表示数是否出现)。然后,遍历这40亿个数,只处理落在第37区间内的数,将这些数在 bitArr 中对应的位置标记为1。

 找到未出现的数: 遍历完所有数后,遍历 bitArr。必然会找到一个位置上的位没有被设置为1。假设第i位上的值没被设置成1,那么未出现的数就是 67,108,864 * 37 + i。

 3)如何确定分块区间

在第一次遍历中我们划分了64个区间,为什么是64个呢?这个要根据限制的空间大小来决定,我们有10MB的空间一次能存83886080个数字,而划分的一个区间就应该在83886080以内。

2. 用2GB内存在20亿个整数中找到出现次数最多的数

题目要求: 有一个包含 20 亿个全是 32 位整数的大文件,在其中找到出现次数最多的数要求,内存限制为 2GB。

  1. 哈希表统计: 通常,我们使用哈希表来对每个数进行词频统计,其中哈希表的键是整数,值是该整数出现的次数。考虑到内存的限制,每个哈希表记录占用8字节(4字节键 + 4字节值),当哈希表记录数达到2亿时,需要至少1.6GB的内存。

  2. 分块处理: 由于内存有限,一次性处理20亿个数可能会耗尽内存,因此需要分块处理。首先,使用哈希函数将20亿个数分成16个小文件,确保相同的数不会散列到不同的小文件中,同时每个小文件中不同数的数量不超过2亿。

  3. 每个小文件的统计: 对每个小文件,使用哈希表来统计其中每种数的出现次数,并找出每个小文件中出现次数最多的数。

  4. 合并结果: 最后,从16个小文件中选择出现次数最多的数,即每个小文件的出现次数最多的数,再从这16个候选数中选择出现次数最多的数,即整个20亿数据集中出现次数最多的数。

3. 从100亿个URL中查找问题

题目: 有一个包含 100 亿个 URL 的大文件,假设每个 URL 占用 64B,请找出其中所有重复的 URL。

补充问题: 某搜索公司一天的用户搜索词汇是海量的(百亿数据量),请设计一种求出每天热门 Top 100词汇的可行办法。

  1. 哈希分流和拆分: 面对大规模数据,首要任务是将数据分流到不同的机器或者将大文件拆分成小文件。这可以通过哈希函数来实现,确保相同的数据不会分配给不同的机器或文件。

  2. 每个分流的处理: 对于每台机器或每个小文件,使用哈希表来记录每种词及其词频。这一步会生成哈希表,其中键是词汇,值是词汇的出现次数。

  3. Top K 选择: 哈希表记录建立完成后,遍历哈希表,并使用一个小根堆(或优先队列)来选择每个小文件的前 K 个词汇(Top K)。这个小根堆的大小通常是 100,但可以根据需求进行调整。

  4. 排序和合并: 每个小文件都有自己的 Top K 词汇,按照词频排序。然后,将每个小文件的排序后的 Top K 词汇进行外部排序,或者继续使用小根堆来合并这些结果。这将得到每台机器上的 Top K 结果。

  5. 全局 Top K 选择: 最后,从每台机器的结果中选择全局的 Top K 结果。这可以通过外部排序或再次使用小根堆来完成。

4. 40亿个非负整数中找到出现两次的数 

题目要求:32 位无符号整数的范围是 0~4 294 97 25,现在有 40 亿个无符号整数,可以使用最多1GB的内存,找出所有出现了两次的数。

可以使用bitmap,申请一个2*4 294 97 25大小的bitmap

第一次出现将bitmap[num*2]和bitmap[num*2+1]的位置设为10

第二次出现将bitmap[num*2]和bitmap[num*2+1]的位置设为01

第三次出现将bitmap[num*2]和bitmap[num*2+1]的位置设为11

以后再碰到bitmap[num*2]和bitmap[num*2+1]的位置为11的就不在设置

遍历结束bitmap[num*2]和bitmap[num*2+1]的位置为01的就是出现了两次的数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值