[Go版]算法通关村第十五关黄金——继续研究超大规模数据场景的问题

海量数据中,此时普通的数组、链表、Hash、树等等结构有无效了 ,因为内存空间放不下了。而常规的递归、排序,回溯、贪心和动态规划等思想也无效了,因为执行都会超时,必须另外想办法。这类问题该如何下手呢?这里介绍三种非常典型的思路:

  1. 使用位存储,使用位存储最大的好处是占用的空间是简单存整数的1/8。例如一个40亿的整数数组,如果用整数存储需要16GB左右的空间,而如果使用位存储,就可以用2GB的空间,这样很多问题就能够解决了。

  2. 如果文件实在太大 ,无法在内存中放下,则需要考虑将大文件分成若干小块,先处理每个块,最后再逐步得到想要的结果,这种方式也叫做外部排序。这样需要遍历全部序列至少两次,是典型的用时间换空间的方法

  3. 如果在超大数据中找第K大、第K小,K个最大、K个最小,则特别适合使用堆来做。而且将超大数据换成流数据也可以,而且几乎是唯一的方式,口诀就是“查小用大堆,查大用小堆”。
    常识补充:10亿 ≈ 1G、100万 ≈ 1M

题目:对20GB文件进行排序

解决思路:外部排序 + 两两合并

  1. 需要先考虑内存要求、时间要求等限制条件,然后根据要求确定需要划分为多少块进行处理。
  2. 比如内存限制为1GB,则将20GB文件分为20块文件。
  3. 对每块文件进行排序。
  4. 最后两两合并即可。(也可以使用堆排序策略合并)

题目:超大文本中搜索两个单词的最短距离

题目要求:有个超大文本文件,内部是很多单词组成的,现在给定两个单词,请你找出这两个单词在这个文件中的最小距离,也就是像个几个单词。你有办法在 O(n)时间 里完成搜索操作吗?方法的空间复杂度如何。
在这里插入图片描述

解决思路:双指针法

使用两个指针来记录两个单词的索引位置,通过遍历文本文件,不断更新这两个指针,以便计算最小距离。

  1. 声明两个指针,初始都默认指向-1;再声明一个变量length,用于接收两个单词的距离。
  2. 遍历这个文本文件,
    • 遇道单词1,就让指针1指向单词1的索引,
    • 遇道单词2,就让指针2指向单词2的索引,
    • 如果指针1和指针2都>0时,算出两指针的距离,如果该距离比<length,就赋值给length。
  3. 遍历完了之后,此时length就是两个单词的最短距离。

复杂度:时间复杂度 O ( n ) O(n) O(n)、空间复杂度 O ( 1 ) O(1) O(1)

题目:从10亿数字中寻找最小的100万个数字

题目要求:设计一个算法,给定一个10亿个数字,找出最小的100万的数字。假定计算机内存足以容纳全部10亿个数字。

解决思路

方案1:对10亿数字做 快速排序,返回前100万个。

对10亿数字做升序的快速排序后,前100万个就是最小的100万个数字了。

复杂度:时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)、空间复杂度 O ( l o g n ) O(logn) O(logn)

所需内存大概4G左右,太高不推荐。

扫描二维码关注公众号,回复: 16429649 查看本文章

方案2:对10亿数字做 选择排序,100万次

对10亿数字做选择排序,每次遍历找到当前最小的数字,遍历100万次就能找到最小的100万个数字了。

复杂度:时间复杂度 O ( n m ) O(nm) O(nm)、空间复杂度 O ( m ) O(m) O(m)

时间复杂度为:10亿*100万次,这个效率一般的服务器都达不到。

方案3【推荐】:维护长度为100万的最大堆

  1. 构建一个长度为100万的最大堆,
  2. 遍历10亿-100万中剩余的数字,依次和堆顶比较,如果 < 堆顶,就跟堆顶交换,然后最大堆化。
  3. 最后该最大堆就是最小的100万个数字。

补充说明:
如果数据量没有这么大,也可以直接使用这种方式。
如果将10亿数字换成流数据,也可以使用堆来找,而且对于流数据,几乎只能用堆来做。

复杂度:时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)、空间复杂度 O ( m ) O(m) O(m)

所需内存为 100万*4B ≈ 4MB ,可以接受。

猜你喜欢

转载自blog.csdn.net/trinityleo5/article/details/132581827