The-Art-Of-Programming-By-July:海量数据习题解答

题目是在https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/06.15.md给出的。

##1 有100W个关键字,长度小于等于50字节。用高效的算法找出top10的热词,并对内存的占用不超过1MB。 提示:老题,与caopengcs讨论后,得出具体思路为:

先把100W个关键字hash映射到小文件,根据题意,100W50B = 5010^6B = 50M,而内存只有1M,故干脆搞一个hash函数 % 50,分解成50个小文件;
针对对每个小文件依次运用hashmap(key,value)完成每个key的value次数统计,后用堆找出每个小文件中value次数最大的top 10; -最后依次对每两小文件的top 10归并,得到最终的top 10。

此外,很多细节需要注意下,举个例子,如若hash映射后导致分布不均的话,有的小文件可能会超过1M,故为保险起见,你可能会说根据数据范围分解成50~500或更多的小文件,但到底是多少呢?我觉得这不重要,勿纠结答案,虽准备在平时,但关键还是看临场发挥,保持思路清晰关注细节即可。

解答:> 也就是“提示”了。

##2 单机5G内存,磁盘200T的数据,分别为字符串,然后给定一个字符串,判断这200T数据里面有没有这个字符串,怎么做? 如果查询次数会非常的多, 怎么预处理?
提示:如果数据是200g且允许少许误差的话,可以考虑用布隆过滤器Bloom Filter。但本题是200T,得另寻良策,具体解法请读者继续思考。

解答:> 将这200T使用Hash映射到多个桶中,判断给出的字符串属于哪个桶,然后在对应的桶里面查找。

##3 现在有一个大文件,文件里面的每一行都有一个group标识(group很多,但是每个group的数据量很小),现在要求把这个大文件分成十个小文件,要求:1、同一个group的必须在一个文件里面;2、切分之后,要求十个小文件的数据量尽可能均衡。

解答:> 如果group标识分布比较均匀,那么hash(group_id) % 10就行了。如果不均匀:那么 方法1:hash(group_id) % 10,并记录每个小文件存放是记录数量以及总记录数量,得到小文件后把偏大的文件里的数据部分转移到偏小的文件中。
**方法2:**利用hash将groupid转换为某一小范围内的数字,假设这一范围是0~200,以数字为key,对每个数字计数。然后借鉴哈夫曼编码的思路,根据计数值将其合并为10个堆。可以认为这10个堆分布比较均匀。这样就可以划分文件了。

##7 服务器内存1G,有一个2G的文件,里面每行存着一个QQ号(5-10位数),怎么最快找出出现过最多次的QQ号。

解答:> 参考25题。

##8 尽量高效的统计一片英文文章(总单词数目)里出现的所有英文单词,按照在文章中首次出现的顺序打印输出该单词和它的出现次数。

解答:> 维护两个hashmap,第一个hashmap的key是出现次序(1,2,3.。。),value是单词;第2个map的key是单词,value是次数。

index = 1
for word in doc:
    if hm2.has_key(word):
        hm2[word] = hm2[word] + 1
    else:
        hm2[word] = 1
        hm1[index] = word
        index += 1
for i = 1...index:
    word = hm1[index]
    print word, hm2[word]

##9 在人人好友里,A和B是好友,B和C是好友,如果A 和C不是好友,那么C是A的二度好友,在一个有10万人的数据库里,如何在时间0(n)里,找到某个人的十度好友。

**解答:>**肯定有一个表维护着好友关系,即每行两个用户id,表示这两个用户是好友。可以使用图的广度遍历搜索,并使用set来维护已经访问过的用户id。

##12 海量记录,记录形式如下: TERMID URLNOCOUNT urlno1 urlno2 ..., urlnon,请问怎么考虑资源和时间这两个因素,实现快速查询任意两个记录的交集,并集等,设计相关的数据结构和算法。

解答:> 用hashmap记录每个url出现次数,最终出现次数大于1的url是交集;hashmap的keySet是并集。 如果每个记录太大,可以考虑拆分为多个记录。

##14 有一亿个整数,请找出最大的1000个,要求时间越短越好,空间占用越少越好。

解答:> 使用最小堆。

##18 10亿个int型整数,如何找出重复出现的数字。

解答:> Hash映射到多个文件,分而治之。对每个文件,使用hashmap来统计。

##19 有2G的一个文本文档,文件每行存储的是一个句子,每个单词是用空格隔开的。问:输入一个句子,如何找到和它最相似的前10个句子。 提示:可用倒排文档。

解答:> 倒排文档是指这样样一个映射,key是单词,value是出现该单词的句子集合(可以先给每个句子分配一个ID)。将输入的句子拆分成单词,假设有k个单词,于是得到 k个句子集合。求出现在k个集合中的出现次数最多的10个句子。

##20 某家视频网站,每天有上亿的视频被观看,现在公司要请研发人员找出最热门的视频。 该问题的输入可以简化为一个字符串文件,每一行都表示一个视频id,然后要找出出现次数最多的前100个视频id,将其输出,同时输出该视频的出现次数。

1.假设每天的视频播放次数为3亿次,被观看的视频数量为一百万个,每个视频ID的长度为20字节,限定使用的内存为1G。请简述做法,再写代码。
2.假设每个月的视频播放次数为100亿次,被观看的视频数量为1亿,每个视频ID的长度为20字节,一台机器被限定使用的内存为1G。

提示:万变不离其宗,分而治之/Hash映射 + Hash统计 + 堆/快速/归并排序。

解答:> 参考25题。

##21 有一个log文件,里面记录的格式为: QQ号 时间 flag 123456 14:00:00 0 123457 14:00:01 1 其中flag=0表示登录 flag=1表示退出 问:统计一天平均在线的QQ数。

解答:> 参考http://blog.csdn.net/hackbuteer1/article/details/7348968

一天总共有3600*24=86400秒。定义一个长度为86400的整数数组intdelta[86400,每个整数对应这一秒的人数变化值,可能为正也可能为负。开始时将数组元素都初始化为0。然后依次读入每个用户的登录时间和退出时间,将与登录时间对应的整数值加1,将与退出时间对应的整数值减1。这样处理一遍后数组中存储了每秒中的人数变化情况。

定义另外一个长度为86400的整数数组intonline_num[86400,每个整数对应这一秒的论坛在线人数。假设一天开始时论坛在线人数为0,则第1秒的人数online_num[0]=delta[0]。第n+1秒的人数online_num[n]=online_num[n-1]+delta[n]。这样我们就获得了一天中任意时间的在线人数。

##22 一个文本,一万行,每行一个词,统计出现频率最高的前10个词(词的平均长度为Len)。并分析时间复杂度。

解答:> 使用trie树或者hashmap统计每个单词出现次数,构造元素(单词次数,单词),根据单词次数快速排序找出最大的10个。

##23 在一个文件中有10G个整数,乱序排列,要求找出中位数。内存限制为2G。只写出思路即可。

解答:> 将这10G个数字放入10个桶中,每个桶保存值在一定范围内的数字,任意两个桶之间值的范围没有重叠。比如第1个桶保存小于1000的数字,第2个桶保存不小于1000、小于20000的数组,...。对每个桶进行计数,很容易得到中位数是在第几个桶,以及是这个桶中第几小的元素。然后就只对这个桶进行处理就行了,如果2G内存放不下这个桶,则对这个桶继续划分桶。最后,可以使用快速排序找到某个桶中第k小的元素,也就是最终的中位数。

##24 一个url指向的页面里面有另一个url,最终有一个url指向之前出现过的url或空,这两种情形都定义为null。这样构成一个单链表。给两条这样单链表,判断里面是否存在同样的url。url以亿级计,资源不足以hash。

解答:> 就是判断两个单链表是否有相同元素。以下整理自http://iam42.iteye.com/blog/1680444

情况一:两条单链表均无环。最简单的一种情况,由于两条链表如果交叉,他们的尾节点必然相等(Y字归并),所以只需要判断他们的尾节点是否相等即可。

情况二:两条单链表均有环。这种情况只需要拆开一条环路(注意需要保存被设置成null的节点,补充:可以在环的任意一处断开),然后判断另一个单链表是否仍然存在环路,如果存在,说明无交叉,反之,则有交叉的情况。

情况三:两条单链表,一条有环路,一条无环路。这种情况显然他们是不可能有交叉的。

##25 一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。

解答:> 散列到1000+个文件中,力求每个文件大小小于1M(大了就再拆)。每个文件找出出现频率最大的100个词(先统计每个单词的数量,得到一系列元组(单词,出现次数),找到最大的100个出现次数,单词也就出来了)。然后对这多个文件归并。由于有基于元组的排序,建议每个小文件200KB~500KB。

##26 1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。请怎么设计和实现?

解答:> 使用hashset或者trie树。 如果内存不够,可以先把这1000万个字符串散列到多个文件中。

##27 有10个文件,每个文件1G,每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。要你按照query的频度排序。

解答:> 重新散列为100个文件,使得同一个query最终放入同一个文件中。对于每个文件可以使用Trie树或者hashmap对每个query计数,并得到(次数,单词1、单词2、...)这种元组,同时根据次数从大到小排序。对这100个文件归并排序。

##28 现有一200M的文本文件,里面记录着IP地址和对应地域信息,如

202.100.83.56 北京 北京大学
202.100.83.120 北京 人民大学
202.100.83.134 北京 中国青年政治学院
211.93.120.45 长春市 长春大学
211.93.120.129 吉林市 吉林大学
211.93.120.200 长春 长春KTV

现有6亿个IP地址,请编写程序,读取IP地址便转换成IP地址相对应的城市,要求有较好的时间复杂度和空间复杂度。

**解答:>**将这200M文件转换为内存中的hashmap。如果有内存限制,可以将200M文件按照IP的第一个字段来划分为26个文件(0~10是一个,10~20是一个、...、250~255是一个),同理将6亿个IP分成26份。两两对应起来,再结合hashmap。

转载于:https://my.oschina.net/letiantian/blog/391912

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值