资源限制类问题

资源限制技巧汇总

  1. 布隆过滤器用于集合的建立与查询,并可以节省大量空间
  2. 一致性哈希解决数据服务器的负载管理问题
  3. 利用并查集结构做岛问题的并行计算
  4. 哈希函数可以把数据按照种类均匀分流
  5. 位图解决某一个范围上数字的出现情况,并可以节省大量空间
  6. 利用分段统计思想、并进一步节省大量空间
  7. 利用堆、外排序来做多个处理单元的结果合并

题目一

32位无符号整数的范围是0~4,294,967,295,
现在有一个正好包含40亿个无符号整数的文件,
可以使用最多1GB的内存,怎么找到出现次数最多的数?

该题是哈希函数的应用
每一个无符号整数都是4Byte,文件中一行有一个整数。无符号整数范围是 0 ~ 2 ^ 32 - 1 即 0 ~ 42 亿+

1GB内存指的Byte

1GB内存做hash表,key代表某一个出现过的数,value是出现的次数
key是无符号整数, value是无符号整数,那么1条数据,可以容得下, 0 ~ 2 ^ 32 - 1的范围内任何一个数

用1GB内存做hash表, 最多可以放几条数据?
key(4Byte) + value(4Byte) 粗略估计一条数据至少 8Byte,假设不算额外的空间
40亿个无符号整数,假设每个数都不一样,那么就有40亿条数据, 40亿 * 8 Byte = 320亿 Byte 约等于 32 G

我们给定1GB内存,所以这个方法是不可行的。

1GB 内存最多能装多少条数据? 40亿 / 32 保守估计:1亿条
1GB内存 -> 1 亿条数据

40亿整数的文件, 读到一个数,用经典的hash函数计算该数的返回值,令其取模40的值建立索引,可以得到0 ~ 39 范围上的索引
我们准备40个文件,编号分别是0 ~ 39,将读取到的数,保存到对应的索引代表的文件中
重复以上操作
即:

f(num1) % 40
f(num2) % 40
f(num3) % 40
...
f(numN) % 40

f(num1) % 40 == 0 则 把该数发货到提前准备好的0号文件中
f(num2) % 40 == 1 则 把该数发货到提前准备好的1号文件中

每次向文件中写入数据都另起一行,不覆盖原数字

因为相同的哈希函数,的输入会导致相同的结果输出,根据哈希函数的性质,同一种数字不可能被发送到不同文件中
不同的数,假设40亿个数中有S种不同的数,取模完以后,我们可以认为0~39号文件中的整数几乎均等
根据哈希函数的特性,均匀离散,比如0号文件中的整数,不会超过1亿种类型,即使超过1亿种,也不会超过太多
用1G内存,统计0号文件中出现最多的数
释放1G内存,统计1号文件,所有的数出现的词频
释放1G内存,统计2号文件
选出40个文件中各自的出现最多的数,比大小,选出最大的即可

即便40亿个数都一样,f(num) % 40 每一次都一样, 只会在一个小文件中,出现40亿个相同的值,
用1G内存统计,只有一条记录,不会爆内存

40亿个数的文档存在硬盘中,硬盘读写使用偏移量,非常快速

题目二

32位无符号整数的范围是0,4,294,967,295,
现在有一个正好包含40亿个无符号整数的文件,
所以在整个范围中必然存在没出现过的数。
可以使用最多1GB的内存,怎么找到所有未出现过的数?
【进阶】
内存限制为10MB,但是只用找到一个没有出现过的数即可
内存限制为3KB, 但是只用找到一个没有出现过的数即可
内存限制为四个变量,但是只用找到一个没有出现过的数即可


位图思想1GB解法:
42亿的量,每个无符号整数占4Byte,共需要160亿Byte的空间,大概是16GB,
采用位图:长度为2 ^ 32 bit的位图,可以表示 0 ~ 2 ^ 32 - 1个数字是否出现过(1:出现过,0:未出现过)
所以空间占用是原来的1/32, 16GB / 32 约等于 500MB空间


10MB (分成段,某一段必定不满)
通用方法,10M和3K是同一种解法

3KB 都做成整型数组,能做多大? 3k / 4 = 750
找一个离 750 最近的2 的某次方的数,即 512 将512作为数组的长度,避免超过规定内存
假设有一个数组是 512 长度 int[512] counts
所有数据的范围是0 ~ 2 ^ 32 - 1
2^32种不同的数,一定能被均匀分成 512 份

2^32 / 512 = 8388608 ,每一份里边有这些个数字
让第0份,统计0~8388608的范围上的词频,出现即counts[0]++
让第1份,统计8388608~2*8388608的范围上的词频,出现即counts[1]++
… counts[i]++
把整个范围均分成了512份,统计的词频不会超过整型的最大范围

范围0,4,294,967,295上,正好包含40亿个无符号整数,所以在某个范围上,他的词频统计一定不足8388608,即在该范围上必缺数字
假如范围是[L,R],继续在该范围上做以上操作,
直到把范围缩小到3KB以内,则用3k空间做位图,刚好可以查出哪个数不存在


四个变量,2分法
L ---------------------M----------------------R
0------------【假设2^31-1】------------2 ^ 32 -1
----- A++ -------------------------- B++ -----

遍历一遍文件,看左侧的词频是多少 [L,M]
如果 0 ~ 2 ^ 32 个数都不重复,且都出现了,那么左侧范围上的词频是 2 ^ 31, 右侧词频也是是 2 ^ 31

遍历40亿个数,左侧右侧必有不满的,如果左侧词频超过2 ^ 31,那么右侧必不满
则 L = M + 1 R = R M重新计算,遍历文件,继续二分下去
直到只剩下一个数的时候,就找到了

最多遍历32次文件即可找到

不只有有序才能二分,无序也可以
鸽笼原理

题目三

有一个包含100亿个URL的大文件,假设每个URL占用64Byte,
请找出其中所有重复的URL
【补充】
某搜索公司一天的用户搜索词汇是海量的(百亿数据量),
请设计一种求出每天热门Top100词汇的可行办法

该题需要向面试官提问,因为给定题目非常模糊

允许一定失误率,用布隆过滤器
不允许失误率怎么做?

可以利用哈希来做,并行计算,使用Map Reduce

利用哈希函数,计算出每个URL的hash值,取模100或取模1000,这看机器数量,我们就当取模1000,则把结果发送到0 ~ 999 机器上
同样的URL会被索引到同一个机器中,减少每一个机器上URL出现的种数,如果单个机器上种类过多,用另外一个hash函数,再将其拆成很多小文件
或用原hash函数求完hash值取模另外一个数
哈希来,哈希去,在种数上几乎均分

同一个URL最终只会进同一个小文件,统计小文件有哪些重复的URL,最后汇总(map reduce)

补充问题
大文件分配到各个机器后,拆成小文件,找出小文件Top100,用外部排序, 最后汇总时,求总的Top100
可以利用堆结构, 二维堆
用大根堆组织各个小文件的数据
每个小文件的顶部元素,再组织成一个大根堆
堆中元素是堆,即可以找出全部机器的Top值

文件1
abc 76
kcf 72

文件2
fct 86
tk 63

文件3
zt 92
fe 60

以大根堆组织

                  zt 92
          fct 86        abc 76

1 zt 92

                   fe 60    zt 文件的下一个 fe 60 顶上来,从顶部做下沉调整
          fct 86        abc 76

                   fct 86
           fe 60         abc 76

1 zt 92 2 fct 86
fct 86 tk 63 上来
fe 60 abc 76

                  tk 63 上来,站不住,所以下去
           fe 60         abc 76

                 abc 76
           fe 60         tk 63

1 zt 92 2 fct 86 3 abc 76
周而复始

题目四

32位无符号整数的范围是0,4,294,967,295,
现在有40亿个无符号整数,
可以使用最多1GB的内存,
找出所有出现了两次的数。 (低于两次,高于两次不关心)

位图思想
用两个bit 表示一个数字出现的频率,不对+1, 超过10 则始终记为11
00 00 00 … 00
0 1 2 … 2^32-1
01 00 00 … 00
0 1 2 … 2^32-1

10 00 00 … 00
0 1 2 … 2^32-1 0 出现了两次 变成了10

10 11 00 … 00
0 1 2 … 2^32-1 假设1 出现次数大于两次 那么其代表位始终保持11

统计所有为10bit的数字,即完成题解

500 MB * 2 = 1GB

题目五

32位无符号整数的范围是0 ~ 4,294,967,295,
现在有40亿个无符号整数,
可以用最多10MB (3KB) 的内存,怎么找到这40亿个数的中位数 偶数个数,返回上中位数,
也就是求第20亿小的数。

0 ~ 2 ^ 32 - 1
分段统计的技巧,同题目二,定位第20亿小的数所在的范围

0,1,2,。。。。。。。。。17
假设第17个文件中的最大范围刚好超20亿,最小范围是19亿多一点
那么,整体的第20亿小,就是第17个文件中范围的第1亿小

题目六

32位无符号整数的范围是0 ~ 4,294,967,295,
有一个10GB大小的文件,每一行都放着这种类型的数字
整个文件是无序的,给你5G的内存空间
请你输出一个10GB大小的文件,就是原文件所有数字排序的结果

map + 小根堆
map:存储数据在堆上的索引,作为索引表
小根堆:存储n个当前的Top值
用一个变量维护最大可选择的边界
(在上浮和下沉小根堆中的元素时,要同步交换map中的索引)

假设有以下例子

[3,2,1,4,5,5,1,3,2,3,4,4,1,2,3]

小根堆可以容下2条数据

map 存一条数据在小根堆上的具体位置,用于加速查找

3:1
2:0

小根堆,目前发现的最大的两个数

             2:1
            /
         3:1

1 比堆顶的值小,略过

4进来

            4:1
            /
         3:1

             3:1
            /
         4:1

交换的时候,在map中同步交换

5进来

           5:1
           /
         4:1
            4:1
           /
         5:1

5进来

            4:1
           /
         5:2

遍历一遍后,小根堆中存放着全局最大的两个数,而且记录了出现次数

           5:2
          /
       6:1

将两个数写入文件

5:2
6:1

用一个单独的变量t 记录旧的堆顶的值:5
新一轮的操作,所有 >= 5 的值直接略过
以此类推,重复以上操作,就会使全部记录都被排好序
估算5GB,使用map和小根堆(他俩记录数一致),最多放多少条数据?
空间估算 小根堆一条记录大小 int + int = 8 字节
map种一条记录大小 int + int = 8 字节
所以,理论一组数据,占用16字节空间
用5G / 16 可以估算出理论可以存储的数据组数,为了保守,我们可以堆其除10
求Bottom10 则用大根堆维护

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

metabit

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值