N道大数据海量信息处理 算法面试集锦

Top K问题想必面试过的盆友都遇到过,好比亿万级数据如何查找前十的请求/IP地址等的Top K问题,还有相似亿万级数据如何在数据库中分页面试

今天在这里总结下,直接上干货很少BB,但愿你们理解后能够在面试中有更好的表现算法

1 Top K

题目:大数据量请求,找出请求次数最多的IP地址数据库

思路:分治+Hash数组

详解:服务器

1)按照天天为单位处理,IP地址有2^32=4G钟取值,因此确定不能把一天的数据量所有读在内存中,咱们假设这里的数据文件为4G的状况(根据实际业务场景变动数据大小便可,算法是不变的)数据结构

2)使用分治思想,把数据分为1024个小文件,IP地址通过Hash函数处理取模%1024,把大文件分红1024个小文件,这样每一个文件只有4MB大小。函数

3)哈希法(扫描两遍,时间复杂度为O(N)),先对每一个小文件创建HashTable(我用的是Python,因此创建字典,若是想字典有序可使用collctions中的Orderdict数据结构),Key为IP地址,Value为出现的次数(初始为0),扫描一遍先建出来HashTable,而后再扫一遍记录每一个IP地址出现的次数。性能

4)再根据每一个文件的HashTable中的Ip地址进行排序,排序指标为出现的次数也就是Value。快排和堆排均可以,我的比较喜欢回答堆排序的思想。若是结果是Top10的状况创建一个大小为10的小根堆,堆顶就是最小的IP地址对应的出现次数,建堆的时间复杂度为O(logN),而后遍历文件中的IP地址的Value。若是大于堆顶(堆顶为最小的出现次数),那么堆顶与当前数值互换,进行堆调整,调整的时间复杂度为O(logN)。最后的小根堆,所得及所求。大数据

2 海量字符串最高的频率查找(Top K变种)

题目:一个G的文件,每一行是一个词,词大小不超过16k,内存限制为1M,返回频率最高的100个词优化

详解: 1)顺序读取文件中的每行,Python中可使用with open方法,with open方法是按照上下文读取文件,并自动关闭文件,因为Python中的读取的流对象是一个可迭代对象因此可使用For循环按照行读取,放心再大的文件都不会溢出。

2)把1G文件分红5000份这样每份大概200K,而后进行Hash取模,把对应行的内容存在对应的文件中,若是其中文件超过1M(哈希冲突致使的),能够把该文件继续按照以前的方法分解为10份或者几份直到知足要求为止。

3)使用Tire树作词频统计(使用HashMap也能够可是前缀树更适合作词频统计),在创建Tire树时多加一个数据项,表示查询的次数,那么就能够表示以某个单词的查询次数。

4)对每一个文件创建最小堆,堆大小为100,词对应的频率存入文件,这样又获得至少五千个文件,而后对文件中的词频进行归并排序

3 10个文件每一个文件1G,放着用户的QUERY,按照QUERY频率排序

详解: 典型的Top K问题

Plan A:

1)顺序读取10个文件,存入10个文件(哈希取模%10),理论上哈希函数会均分在10个文件中,每一个文件大概为1G大小。

2)电脑内存为2G,创建HashTable,K-V键值对为QUERY-QUERY_TIMES,扫描一遍文件count全部QUERY的出现次数。

3)最后根据Value:QUERY_TIMES进行排序,单个文件使用随机快排 ,堆排序常数项时间复杂度大于快排,而且在工程中寻址时间也长,因此致使理论上大数据量堆排序快于快排,可是实际效果仍是不如快排,排序好的数据存入文件,这样获得了10个独立有序的文件

4)对10个独立有序的文件进行归并排序

Plan B:

1)通常来讲QUERY只是重复的次数多,因此若是考虑一次性读入内存中。

2)扫描一遍内存中的QUERY,而后创建Tire树或者HashMap。Tire树扫描一遍就能够得到词频数据,而HashMap要扫两边,虽然都是O(N),可是HashMap是2N,Tire是N,而后存为文件。

3)直接使用随即快排

4 两个文件各存50亿个url,每一个url64个字节,内存限制4G,找出A,B共同的url

1)单个文件读取确定超出内存大小,因此仍是采起以前的分治思想,大化小,对A/B分别取模分红1000个文件存储。50亿url算下来每一个文件300M。

2)对小文件求公共url的时候可使用set去重。或者使用并查集的IsSameSet判断,缺点是创建十个集合。A文件Set创建后另一个文件的内容遍历跟Set中内容比对,若是相等则记录

另:能够考虑使用BloomFilter,后面的黑名单问题中会详解BloomFilter的

5 N亿个数找出一个只出现一次的数

**详解:**思路跟以前同样,首先分红小文件,而后创建HashTable/tire树进行统计,差异仍是Tire树只须要扫一遍,HashTable须要扫两遍

**另外:**可使用BitMap,每一个数分配两Bit,00不存在,01出现一次,10出现屡次,11没意义。须要内存2^32*8bit=1G,创建完毕扫描数据把对应位置的比特位描成00/01/10/11,最后查找01

6 有一百多万个黑名单,如何判断某个用户是否被拉黑

BloomFilter最佳应用场景

BloomFilter介绍: 布隆过滤器属于BitMap的变种。HashMap若是长度有限,数据量很大的状况下,采用拉链法解决哈希冲突会致使链过长而查询性能受到影响,采用地址开方法(Python中字典使用的解决Hash冲突的方法),那么仍是会致使空间不足。因此想节省空间Bitmap就诞生了。也就是说BloomFilter优势就是省空间,可是布隆过滤器的缺点就是会有失误率。这个失误率是指原本A不属于黑名单,可是被误判进了黑名单,宁肯杀错,毫不放过的一种失误。

原理: 1.某个Key须要加入集合中,须要K个哈希函数计算出K个hash值,并查询对应的比特位,若是全部的比特位对应的值都是1,那么就认为这个Key是在这个集合中的,相比HashMap不须要存储Key节省空间

结构: 集合中每个位置为比特,非0即1,一个Int型整数,4个字节,32个比特,即一个1000的集合,能够表示32000个比特位,数组的InteIndex表示数组中的位置,BitIndex为数组中某一位的比特。根据计算出来的hash值来描黑,最后由该位置的32Bit数或上左移的BitIndex位的1实现

JavaCode

应用到案例: 黑名单问题,url通过k个hash函数进行处理后模个m,对应0~m-1上的一个,算出位置描黑,有可能不一样url打在同一位置,重复描黑。若是k个位置都是黑的那么,这个url就在黑名单里

失误率控制

经过控制m长度和k来控制失误率

肯定数组长度M M=-(n*lnp)/(ln)^2,n是样本量,p预期失误率,算出来是bit,对应的实际字节数应该除以8

附加题

题目:千万级数据分页如何实现?

思考:海量数据分页已经没法使用数据库内的分页方法LIMIT,由于这样会严重影响性能。常见的解决方法有两种:1.将查询数据读入内存中,而后在内存中分页,限制每次的查询量 2.采用存储过程分页,不一样数据库实现方式不一样,而且性能达不到预期

优解:

1)在待查询的表中添加一个自增加字段,Query_ID,主键自增加。按照大小顺序逆序排列数据。

语句: SELECT QUERY_ID FORM TABLE WHERE XXX ORDER BY DESC

由于只是查找QUERY_ID字段因此,即便数据量很大查询速度也是很快的,而后将查询到的QUERY_ID保存应用服务器的一个数组中

2)用户在客户端进行翻页的时候,客户端将查询的页号做为参数传递给应用服务器。服务器经过页号和QUERY_ID数组计算出待查询的最大值和最小值,而后查询。

计算QUERY_ID最大最小值: 定义page:待查询的页号;pagesize为每页的大小;query_ids为以前生成的数组

优势:

1)全部数据库都适用

2)CPU和内存占用较低

3)查询速度较快

物理优化:

1)数据分区

2)增长内存

3)数据分表

还能够分红两个库,一个作查询,一个作事务

....三天终于写完了

相关文章
相关标签/搜索