top k问题
即在很多数据的情况下选出前k大的数据,数据量可上亿
要分情况讨论,
如果是堆排序,时间复杂度是O(lgn)级别,,比较次数和交换次数相同,平均为logn/2,
可以采用插入排序的办法,只维护一个k的数组,按降序排列,只用在中间插入并删掉超过k的部分,这个时间复杂度为O(n),平均比较次数为O(n/2),移动次数是O(n/2),如果可以做成链表结构,则还能省去移动的开销,而只用在比较完成后修改指针
大数据排序
如果是上亿的数据,常规的办法:加载到内存并用经典算法是行不通的,内存没办法装下那么多数据,一种解决办法是用数据库来建立索引从而排序,要保证数据库要能容纳这么多数据
另一种解决是分治,,可以用哈希来把大文件映射到相同大小,小到能用内存装下,从而分批操作,最后用外排来两两合并成同一个文件,这即是归并排序的思想,归并的时候
分治的一个好处是如果有多机可以分块后并行操作
如果是不重复的数据,可以采用桶排序的思想,每一位代表一个数字,用上亿个bit位,也不过几百MB,可以读进内存;操作方法是先初始化这个bit数组位0,接着遍历一遍数据,对每个数字对应的bit位置1,最后按这些bit位写进另一个文件中,可以做到O(n)的排序
找重复
如果是知道界限的,不同的数字都能用一个bit表示,哪怕上亿的数据也只需几百MB的bit图,一个重复出现的数字设置bit图的时候会发现已经被设过了
找重复url
两个大文件,各含有很多url,找两个里面重复的url
因为是URL找相同,不能用bitmap来代表每个URL,要用常规办法,就得把URL装入内存,需要两边分别hash后取模,左右若相同的URL会落到相同序号的文件,然后用hashmap来把判断左右相同序号的文件里相同的URL
找不重复的数字
(用分治的思想,把文件切分到内存可容纳的大小后用)
用位图的方法,不过因为不重复,每个数字要用两个bit,也就翻倍而已
数据去重
问题:
- 每个ID判断是否是第一次添加,或者说数据去重,是否是第一次添加也可以看成是有无标记,
- 如何对短时间内的大量请求访问进行限流
- 场景题:QQ的服务器会保存登录用户的QQ号,只要有登录,文件里面就会有记录,现在需要统计哪些QQ号登录过,怎么做?(先说了分治用小文件,他说除了这个了,我说bit数组,他就问需要多大内存?)
解决方案
可以采用数据库,每次加入看是否是第一次加入,但是如果数据很长,是URL或者很长的int会开销比较大,而且存在磁盘中访问比较慢
如果知道了数据的区间是连续的较密集的int,可以采用bitmap,能判断是否第一次且能去重
判断是否是黑名单,也是类似用法,如果是字符串类型如url,则无法用bitmap
另一种方法是用哈希,标记哈希完的值以节省空间,为了减少碰撞的危害,采用多种hash分别存储,如果一个字符串在多个hash完的记录里都存在,即被标记过(也可能碰撞),这就是布隆过滤器
总结
首先以下都能用数据库来解决
标记数据
如果是知道范围且不重复的数字,可以用bit位图表示,n个数据就是n个bit的大小
bitmap如果排列很稀疏,可以用谷歌的Enhanced Word-Aligned Hybrid算法,不在讨论范围内
如果是字符串类型比如URL,可以用多个哈希来标记如布隆过滤器
排序
对于大数据可以采用分治的思想,采用hash+取模就是一种划分的方法
如果要排序,可以采用分治+外排,即归并排序
- 当然如果能了解下比如hdfs文件系统,一致性哈希,mapreduce,spark/flink流式计算最佳哈
如何并行
并行一个是拆分任务,一个是合并结果
拆分任务要保证任务间不重叠,最好是保证均匀划分,如果是处理数据,可以用哈希+取模的方式来分配
问题
- 如何对短时间内的大量请求访问进行限流
- 有200亿qq,但实际只有25亿用户,找到重复的qq,25亿qq占用内存多大
- 1-100万,计算找出所有的质数(计算密集型任务),用单线程与多线程怎么处理
- 1个G的文件写程序,从A机器发送到B机器,怎么发?
- 100G的文本,每行80k还是80字符,提示用多个机器,多进程,多线程,求出重复最多的行。一个机器内存8G,计算每个机器大概分多少?能读取100G的文本吗?找重复率前十的文本
- 三个有序的序列,查找公共的部分,第一次我说用哈希表,他说序列太大,空间复杂度要低点,我说了二分查找,他问三个序列查找的顺序和时间复杂度。(时间复杂度为N*logN *logN)
- 100WURL,如何存储
- 10台服务器,100w用户,如何进行负载均衡,如何有个服务器挂掉了咋 办
- 地铁问题: 统计地铁 某一秒的 人数 数据: 时间都到秒级别 进站时间 出站时间 卡ID;;方法: 1、用一个数据a[60*60*24]来表示每一秒的变化人数,比如第10秒,进入100人,a[10]+=100,出站20人,a[10]-=20那么最终a[10] = 80。 2、再用另外一个同大小数组b[0] = a[0] b[i] = b[i-1] + a[i] 就是第I秒前的总人数 重点: 考虑每秒变化的人数!