大数据算法学习笔记

一、高频考题:有100亿个无序数字,只有一台电脑,给100亿个数字排序

1.1、分析

100亿个 int 型数字放在文件里面大概有 37.2GB,非常大,内存一次装不下了。那么肯定是要拆分成小的文件一个一个来处理,最终在合并成一个排好序的大文件。

1.2、解题思路

Step1、把大文件hash成多个小文件

把这个37GB的大文件,用哈希分成1000个小文件,每个小文件平均38MB左右(理想情况),把100亿个数字对1000取模,模出来的结果在0到999之间,每个结果对应一个文件,所以我这里取的哈希函数是 h = x % 1000,哈希函数取得"好",能使冲突减小,结果分布均匀。

Step2、对小文件逐个排序

拆分完了之后,得到一些几十MB的小文件,那么就可以放进内存里排序了,可以用快速排序,归并排序,堆排序等等

Step3、把有序的小文件合并成一个有序的大文件

1、首先遍历1000个文件,每个文件里面取第一个数字,组成 (数字, 文件号) 这样的组合加入到堆里(假设是从小到大排序,用小顶堆),遍历完后堆里有1000个 (数字,文件号) 这样的元素

2、然后不断从堆顶拿元素出来,每拿出一个元素,把它的文件号读取出来,然后去对应的文件里,加一个元素进入堆,直到那个文件被读取完。拿出来的元素当然追加到最终结果的文件里。

3、按照上面的操作,直到堆被取空了,此时最终结果文件里的全部数字就是有序的了。

二、大数据考题

1. 海量日志数据,从中提取出某日访问百度网站次数最多的那个IP.

解题思路:分治算法(hashcode取模+map/reduce)

1)要查IP, 先要知道一共最多有多少IP存在,IPV4最多有2的32次方,IPV6最多有2的48次方。对于2的32次方,占用4G空间,不可能一次全部加载到内存中。

2)可采用分治法:将其分成n个子部分,分别计算。例如分成1000份,可采用hashcode绝对值取模的方法,对所有的IP进行负载均衡分配,即分配到1000个小文件中,然后找出每个小文件中出现频率最大的几个IP(通过HashSet),最后对这1000个文件进行汇总,找出频率最大的IP,即为所求。

2. 搜索引擎会通过日志文件,把用户每次检索使用的所有的关键字记录下来,每个关键字的长度是1~255字节。假设有一千万个记录(这些搜索关键字的重复度较高,一千万去重后,不到三百万个,一个关键字重复度越高,说明查询它的用户越多,就越热门)。题目:要求统计最热门的10个查询关键字,要求使用的内存不能超过1G.

解题思路:分治法

1)先使用HashSet对一千万个搜索关键字去重(借助HashSet+Hashcode取模),得到每个关键字的出现频率,时间复杂度为O(n)

2)借助堆数据结构(树顶元素最大,只需要维护10个元素,然后如果找到比树中某元素大的,则插入到当前元素,然后重新调整堆),找出top K, 这样时间复杂度为N*logK

总结:借助“堆”这种数据结构,我们可以在log量级时间内查找和移动。即在题目中,维护一个K(这里K为10)大小的堆,然后遍历300万的数据,分别和根元素对比,最终的时间复杂度为:O(N) + O(n*logk), 其中N为1000万;n为300万;k为10。

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

解题思路:

1)遍历每一个词,用hashcode绝对值取模的方式,负载均衡到5000个小文件中,这样每个文件是200k左右。如果其中有的文件超过了1M大小,那么用这种方法继续分,直到每个小文件的大小都不超过1M。

2)然后对每个文件,统计出词出现的频率(如hashmap或者trie树),并取出出现频率最大的100个词(可以用含100个节点的最小堆),并把这100个文件进行归并(类似于归并排序)。

  1. 给定a, b两个文件,各存放50亿个url, 每个url占64字节,内存限制是4G,要求:找出a, b文件共同的url.

解题思路:

1)50个亿约等于5G, 每个64字节,5G*64 = 320G, 远大于4G内存限制。所以采用分治法。

2)遍历50亿个url, 用hashcode取模的方式,平均分到1000个文件中。即a分到a1, a2, … , a1000; b分到b1, b2, … , b1000。这样,每个文件大约300M。

3)比较a1和b1, a2和b2, … , a1000和b1000。每对文件采用HashSet来查询是否有重复。

  1. 在2.5亿个整数中找到不重复的整数,注,内存不足以容纳这2.5亿个整数。

解题思路:也将这2.5亿个文件平均分配到n个文件中,然后将单个文件中重复的数删除,对剩下的整数排序。最后再对这n个文件进行归并。

  1. 腾讯面试题:给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个整数,如何快速判断这个数是否在那40亿个数中?

解法1. 申请512M内存,一个bit代表一个unsigned int,读入40亿个数,设置到相应的bit位上,读入要查询的数,查看相应的bit是否为1,1表示存在,0表示不存在。

解法2. 因为2的32次方为40多亿,我们把40亿个数用一个32位的二进制数来表示。(节省内存)

这40亿个数,转成2进制后,最高位为1的,表示大于2亿;最高位为0的,表示小于2亿。这样,把这40亿个数分成2个文件,一个文件存放最高位为1的,一个文件存放最高位为0的。

然后在对这两个文件进行分类,次高位为1的放一个文件,次高位为0的放一个文件,以此类推。

这样,在这40个亿个文件中进行查找时,类似于2分法查找,时间复杂度为O(logn)

二。Top K 问题经典解法

海量数据处理 - 10亿个数中找出最大的10000个数(top K问题)

思路:最小堆(即堆顶的元素最小),堆实际上是个完全二叉树
先拿10000个数建立个堆,然后依次添加剩余元素,如果大于堆顶的数(10000个数中最小的),将这个数替换堆顶,并调整结构,使之仍然是一个最小堆。这样,遍历完后,堆中的10000个数是所需的做大的10000个。建堆的时间复杂度是O(mlogm), 算法的时间复杂度是O(nmlogm), 其中n为10亿,m为10000个。

优化的方式:把所有10000个数分组存放,比如分别放在1000个文件中,这样每个文件需要查找的数可以降低1000倍,最后再归并到一起。

  1. top K 问题:在海量数据中找出出现频率最高的前k个数,或者从海量数据中找出最大的前k个数,这类问题通常被称为top K问题。例如,在搜索引擎中,统计搜索最热门的10个查询词;在歌曲库中统计下载最高的前10首歌等。

解决方案:针对top K问题,推荐的解决方案是:分治法 + Tire数/hash + 最小堆。即先将数据集通过hashcode取模的方式分解成多个小的数据集,然后通过Tire树或HashMap统计每个小数据集中的query词频,之后用最小堆求出每个数据集中出现频率最高的前K个数,最后在所有topK中求出最终的top K.

  1. top K的不同场景下的不同的最优解决方案

题目:有1亿个浮点数,如果找出期中最大的10000个?

1)单机、单核、内存足够大

float类型的数占4个字节,1亿个数,占内存10^8*4=400M, 如果有足够内存的话,可以直接用最小堆来解决。

2)单机、多核、内存足够大

将数据通过hash,分成n份,可利用Fork/Join框架,同时多线程处理,最后再进行归并。

3)单机、单核、受限内存

将原数据分级hash到n个小文件中,如果单个小文件仍然大,则继续拆分,直到每个小文件的大小比内存小。然后采用1的方法依次处理小文件,最后再对结果进行归并。

4)多机、受限内存

采用map/reduce方式利用hadoop来计算。单机处理+结果合并。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值