面试:算法实战篇

1. URL黑名单(布隆过滤器)
100亿黑名单URL,每个64B,问这个黑名单要怎么存?判断一个URL是否在黑名单中

2. 词频统计(分文件)
2GB内存在20亿整数中找到出现次数最多的数

通常做法是使用哈希表对出现的每一个数做词频统计,哈希表的key是某个整数,value记录整数出现的次数。本题的数据量是20亿,有可能一个数出现20亿次,则为了避免溢出,哈希表的key是32位(4B),value也是 32位(4B),那么一条哈希表的记录就需要占用8B。
当哈希表记录数为2亿个时,需要16亿个字节数(8*2亿),需要至少1.6GB内存(16亿/2^30,1GB== 2 ^30个字节 ==10亿)。则20亿个记录,至少需要16GB的内存,不符合题目要求。
解决办法是将20亿个数的大文件利用哈希函数分成16个小文件,根据哈希函数可以把20亿条数据均匀分布到16个文件上,同一种数不可能被哈希函数分到不同的小文件上,假设哈希函数够好。然后对每一个小文件用哈希函数来统计其中每种数出现的次数,这样我们就得到16个文件中出现次数最多的数,接着从16个数中选出次数最大的那个key即可。

3. 未出现的数(bit数组)
①40亿个非负整数中找到没有出现的数

建立一个包含40亿个数据的bit数组,数组大小为4294967295,大概为40亿bit,40亿/8 = 5亿字节,那么需要0.5G 空间。每个数据只有0和1两个值,逐个遍历40亿个无符号数,例如,遇到20,则bitArray [20] = 1;遇到666,则bitArray[666] = 1,遍历完所有的数,将数组相应位置变为1。

②40亿个非负整数中找到一个没有出现的数,内存限制10MB

按照上面的处理,正常全量需要512M空间,现在只有10M,那么可以将40亿个数按大小分为64份,存入64个文件中,从最小的一个文件中开始读入内存中的bitArray,直到找到未出现的数。

③40亿个无符号整数,1GB内存,找到所有出现两次的数

申请一个长度为4294967295×2的bit类型的数组bitArr,用2个位置表示一个数出现的词频。逐个遍历40亿个无符号数,例如,遇到20,则bitArray [40] = 0 & bitArray [41] = 1;再次遇到20,则bitArray [40] = 1 & bitArray [41] = 0;第三次遇到20,则bitArray [40] = 1 & bitArray [41] = 1;第四次及以后发现两个位置都是1后,就不再更新。最后遍历bitArray,发现bit[2i]和bit[2i+1],那么i就是出现了两次的数。

4. 重复URL(分机器)
找到100亿个URL中重复的URL

原问题的解法使用解决大数据问题的一种常规方法:把大文件通过哈希函数分配到机器,或者通过哈希函数把大文件拆成小文件。一直进行这种划分,直到划分的结果满足资源限制的要求。首先,你要向面试官询问在资源上的限制有哪些,包括内存、计算时间等要求。在明确了限制要求之后,可以将每条URL通过哈希函数分配到若干机器或者拆分成若干小文件,这里的“若干”由具体的资源限制来计算出精确的数量。
例如,将100亿字节的大文件通过哈希函数分配到100台机器上,然后每一台机器分别统计分给自己的URL中是否有重复的URL,同时哈希函数的性质决定了同一条URL不可能分给不同的机器;或者在单机上将大文件通过哈希函数拆成1000个小文件,对每一个小文件再利用哈希表遍历,找出重复的URL;或者在分给机器或拆完文件之后,进行排序,排序过后再看是否有重复的URL出现。总之,牢记一点,很多大数据问题都离不开分流,要么是哈希函数把大文件的内容分配给不同的机器,要么是哈希函数把大文件拆成小文件,然后处理每一个小数量的集合。

5. TOPK搜索(小根堆)
海量搜索词汇,找到最热TOP100词汇的方法

最开始还是用哈希分流的思路来处理,把包含百亿数据量的词汇文件分流到不同的机器上,具体多少台机器由面试官规定或者由更多的限制来决定。

6.中位数(单向二分查找)
10MB内存,找到100亿整数的中位数

方法:按二进制从最高位开始不断寻找中位数
假设100亿个数字保存在一个大文件中,依次读一部分文件到内存(不超过内存的限制),将每个数字用二进制表示,比较二进制的最高位(第32位,符号位,0是正,1是负),如果数字的最高位为0,则将这个数字写入 file0文件中;如果最高位为 1,则将该数字写入file1文件中。从而将100亿个数字分成了两个文件,假设 file0文件中有 60亿 个数字,file1文件中有 40亿 个数字。那么中位数就在file0 文件中,并且是 file0 文件中所有数字排序之后的第 10亿 个数字。(file1中的数都是负数,file0中的数都是正数,也即这里一共只有40亿个负数,那么排序之后的第50亿个数一定位于file_0中)
现在,我们只需要处理 file0 文件了(不需要再考虑file1文件)。对于 file0 文件,同样采取上面的措施处理:将file0文件依次读一部分到内存(不超内存限制),将每个数字用二进制表示,比较二进制的 次高位(第31位),如果数字的次高位为0,写入file00文件中;如果次高位为1,写入file01文件 中。
现假设 file00文件中有30亿个数字,file01中也有30亿个数字,则中位数就是:file00文件中的数字从小到大排序之后的第10亿个数字。
抛弃file01文件,继续对 file00文件 根据 次次高位(第30位) 划分,假设此次划分的两个文件为:file000中有5亿个数字,file001中有25亿个数字,那么中位数就是 file00_1文件中的所有数字排序之后的 第 5亿 个数。
按照上述思路,直到划分的文件可直接加载进内存时,就可以直接对数字进行快速排序,找出中位数了。

7. 短域名系统(缓存)
设计短域名系统,将长URL转化成短的URL.

(1)利用放号器,初始值为0,对于每一个短链接生成请求,都递增放号器的值,再将此值转换为62进制(a-zA-Z0-9),比如第一次请求时放号器的值为0,对应62进制为a,第二次请求时放号器的值为1,对应62进制为b,第10001次请求时放号器的值为10000,对应62进制为sBc。
(2)将短链接服务器域名与放号器的62进制值进行字符串连接,即为短链接的URL,比如:t.cn/sBc。
(3)重定向过程:生成短链接之后,需要存储短链接到长链接的映射关系,即sBc -> URL,浏览器访问短链接服务器时,根据URL Path取到原始的链接,然后进行302重定向。映射关系可使用K-V存储,比如Redis或Memcache。

8. 海量评论入库(消息队列)
假设有这么一个场景,有一条新闻,新闻的评论量可能很大,如何设计评论的读和写

前端页面直接给用户展示、通过消息队列异步方式入库
读可以进行读写分离、同时热点评论定时加载到缓存

9. 在线/并发用户数(Redis)
显示网站的用户在线数的解决思路

维护在线用户表,记录用户的登录时间和登出时间
使用Redis统计

显示网站并发用户数

  1. 每当用户访问服务时,把该用户的 ID 写入ZSORT队列,权重为当前时间
  2. 根据权重(即时间)计算一分钟内该机构的用户数Zrange
  3. 删掉一分钟以上过期的用户Zrem

10. 热门字符串(前缀树)
假设目前有 1000w 个记录(这些查询串的重复度比较高,虽然总数是 1000w,但如果除去重复后,则不超过 300w个)。请统计最热门的 10 个查询串,要求使用的内存不能超过 1G。(一个查询串的重复度越高,说明查询它的用户越多,也就越热门。)

前缀树法
当这些字符串有大量相同前缀时,可以考虑使用前缀树来统计字符串出现的次数,树的结点保存字符串出现次数,0表示没有出现。
思路如下:
在遍历字符串时,在前缀树中查找,如果找到,则把结点中保存的字符串次数加 1,否则为这个字符串构建新结点,构建完成后把叶子结点中字符串的出现次数置为 1。
最后使用小顶堆来对字符串的出现次数进行排序。

11. 红包算法

线性切割法:一个区间切N-1刀。越早越多
二倍均值法:【0 ~ 剩余金额 / 剩余人数 * 2】中随机,相对均匀

12. 大批量IP黑名单压缩存储

直接使用varchar(16)存储比较占空间,并且索引也比较大。使用UNSIGNED INT是4字节长整数进行存储。
使用mysql内置函数INET_ATON() 将IP转换成整数,INET_NTOA() 数字反向转换成IP。
算法: 第一位乘256三次方+第二位乘256二次方+第三位乘256一次方 + 第四位乘256零次方

SELECT INET_ATON('127.0.0.1');
SELECT INET_NTOA('2130706433');
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值