文章目录
方法和工具
1 分治 [包含分布式处理MapReduce]
- 执行步骤
- 【Map】根据
Hash(object) % 1024
将大文件中的所有对象划分到若干个(示例为1024个)小文件(如果有多台机器,将数据按哈希值划分到不同的机器上处理) - 每个小文件在内存中执行一些方法,获得每个小文件的最大值
- 【Reduce】对每个小文件的最大值进行归并,获得目标
- 【Map】根据
- 另一种分治思路【重点在分】:元素范围很大,需要多次划分,逐步确定范围,然后最后在一个可以接受的范围内进行搜索
- 例如寻找 50 亿 int 的中位数
- 将 int 划分为2^16个区域,然后读取数据统计落到各个区域里的数的个数
- 根据统计结果就可以判断中位数落到哪个区域,以及它是这个区域的第几大的数
- 再次扫描该区域,利用内存方法获取中位数【例如维护一个最大堆,一个最小堆】
2 堆
- 适用于 TOPK 问题
- 要求 K 比较小,堆中数据可以完全放入内存
3 哈希
4 位图 / 布隆过滤器
- 布隆过滤器是对位图的扩展,将适用领域推广到了字符串等数据结构
- 适用于查找和去重
- 位图尤其适用于整数问题
5 前缀树 TrieTree
- 适用于数据量大,重复多,但是数据种类少(例如对大量的字符串去重)
常见问题
1 找出某日访问百度次数最多的 IP
- 分治
- 根据
Hash(IP) % 1024
将大文件中的所有 IP 地址划分到若干个(示例为1024个)小文件 - 每个小文件在内存中执行一些方法,获得每个小文件的最大值
- 对每个小文件的最大值进行归并,获得目标 IP
- 根据
2 找出查找次数最多的 10 个查询串(TOPK)
- 内存排序,要求内存可以容纳去重之后的所有查询串(此处堆排序)
- 使用
HashMap
统计每个串出现的次数 - 使用容量为 10 的最小堆,遍历即可获得查找次数最多的 10 个查询串
- 使用
- 分治
- 如果不能容纳,则将其划分为若干个小文件,每个小文件执行上述过程,然后使用最小堆合并
3 找出 A 和 B 两个文件中共同的 URL
- 分治
- 使用相同的哈希函数,将
A 划分为 (A_0, A_1 ... A_n)
,B 划分为 (B_0, B_1 ... B_n)
(不同的 URL 不可能分布在不同的小文件中) - 执行 n 次
A_i
和B_i
的查询,此时两个文件可以加载到内存中,将A_i
的所有 URL 放入HashSet
中,然后遍历B_i
即可找到重复的 URL - 合并 n 对小文件的结果
- 使用相同的哈希函数,将
- 布隆过滤器(数据规模大/哈希函数设计不合理时,有一定错误率)
- 根据内存限制,设计位向量长度
- 计算并存储 A 的所有 URL 的位向量,遍历 B 即可获取结果
4 找出 2.5 亿个整数(内存无法容纳)不重复的整数
- 分治
- 按最低的N位划分成2^N个部分
- 每部分利用内存方法,例如 Set,找出不重复元素
- 合并结果
- 位图
- 每个数分配 2bit,00表示不存在,01表示出现一次,10表示出现多次,11暂时不用
- 扫描所有整数并维护位图
- 遍历位图获取状态为01的整数
5 判断 40 亿无序整数中是否包含某个数
- 按位二分
- 将这40亿个数分成两类:最高位为0、最高位为1,并将这两类分别写入到两个文件中
- 与要查找的数的最高位比较并接着进入相应的文件再查找,递归执行
- 位图
- 每个数分配 1bit,0代表数组中没有当前元素,1代表有
- 扫描所有整数并维护位图
- 查看目标的 bit 是否为1