算法通关村第十五关——从40亿个数中产生一个不存在的数的处理方法

这篇具有很好参考价值的文章主要介绍了算法通关村第十五关——从40亿个数中产生一个不存在的数的处理方法。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.从40个亿中产生一个不存在的整数

题目要求:给定一个输入文件,包含40亿个非负整数,请设计一个算法,产生一个不存在该文件中的整数,假设你有1GB的内存来完成这项任务。****

解题中心思想:存储的不是这40亿个数据本身,而是其对应的位置。

本题不用写代码,能把方法过程说清楚就可以。

1.1 位图存储大数据的原理

方法8 bit1B,一个32位整数需要4B的存储空间,40亿个数就是 40亿 * 4B,约为16GB,用位图来做的话会更节省空间,因为位图的每个位置只能用0或1进行状态表示,这样就只需要40亿 / 8 = 5亿字节,也就是大约500M的存储空间。

过程:具体来做就是先遍历这40亿个数,并把遍历的每个数在位图上的相对位置设置为1。这40亿个数遍历结束后,开始遍历位图,看看哪个位置上的状态为0,就说明这个位置对应的数没有在40亿个数中出现,位图遍历结束后就能得到所有未在40亿个数中出现过的数。

1.2 使用10MB来存储呢?

如果使用10MB来存储,位图也搞不定了,这个时候就得使用分块思想,用时间换空间,通过两次遍历来处理。

40亿个数需要约500MB的空间,如果只有10MB的空间,至少需要50个块才可以。一般划分块都使用2的幂次方的整数倍,此处划分为64个块是合理的。

首先将 0 − 2 32 0-2^{32} 0232 这个范围的数平均分成64个区间,每个区间是67 108 864个数,因为一共只有40亿个数,所以在统计每一个区间上的数有多少时,肯定会有至少一个区间上的计数小于67 108 864。利用这一点可以找出其中一个没出现过的数。具体过程如下:

第一次遍历:先申请长度位64的整型数组countArr[0, ..., 63]countArr[i]用来统计区间i上的数有多少。遍历40亿个数,跟去当前数是多少来决定哪一个区间上的计数增加。比如,如果当前数为2 567 278 1892 567 278 189 / 67 108 864 = 38 ,所以第38个区间上计数增加countArr[51]++。遍历完40亿个数之后,遍历countArr,必然会有某一个位置上的值(countArr[i])小于67 108 864,表示第i区间上至少有一个数没出现过。

此时使用的内存是非常小的,是countArr的大小(64 * 4B)

假设找到第37区间上的计数小于67 108 864,那么对这40亿个数据进行第二次遍历:

  1. 申请长度为67 108 864的位图(bit map),占用大约8MB的空间,记为bitArr[0, ... , 67108863]
  2. 遍历这40亿个数,此时的遍历只关注落在第37区间上的数,记为num(num满足 num / 67108864 = == 37),其他区间的数全部忽略。
  3. 如果步骤2的num在第37区间上,将bitArr[num - 67108864 * 37]的值设置为1,也就是只做第37区间上的数的bitArr映射。
  4. 遍历完40亿个数之后,在bitArr上必然存在没被设置成1的位置,假设第i个位置上的值没被设置成1,那么67108864 * 37 + i这个数就是一个没出现过的数

步骤小结:

  • 根据 10MB 的内存限制,确定统计区间的大小,就是第二次遍历时的 bitArr 大小。
  • 利用区间计数的方式,找到那个计数不足的区间,这个区间上肯定有没出现的数。
  • 对这个区间上的数做 bit map 映射,再遍历bit map,找到一个没出现的数即可。

1.3 如何确定分块的区间

上面的例子中,采用两次遍历,第一次将数据分成64块刚好解决问题,为什么不是128块,32块,16块或者其他块数呢?

这是主要为了保障第二次遍历时每个块都能放进这10MB的空间中。 2 23 < 10 M B < 2 24 2^{23} < 10MB < 2^{24} 223<10MB<224,而 2 23 = 8388608 2^{23} = 8388608 223=8388608 大约是8MB,也就是说我们一次的分块大小只能为8MB左右。我们在第二次遍历时分成64块刚好满足要求,这是最少得分成64块,当然如果分成128块、256块也是可以的。文章来源地址https://www.toymoban.com/news/detail-709227.html

到了这里,关于算法通关村第十五关——从40亿个数中产生一个不存在的数的处理方法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法通关村第十八关——排列问题

    LeetCode46.给定一个没有重复数字的序列,返回其所有可能的全排列。例如: 输入:[1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] 元素1在[1,2]中已经使用过了,但是在[2,1]中还要再使用一次,所以就不能使用startlndex了,为此可以使用一个used数组来标记已经选择的元

    2024年02月09日
    浏览(45)
  • 算法通关村第十七关——跳跃游戏

    leetCode55 给定一个非负整数数组,你最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度,判断你是否能够到达最后一个位置。 示例1: 输入:[2,3,1,1,4] 输出:true 解释:从位置 0 到 1 跳 1 步,然后跳 3 步到达最后一个位置。 示例2: 输入:[3

    2024年02月10日
    浏览(37)
  • 算法通关村第十九关——最小路径和

    LeetCode64. 给定一个包含非负整数的 m × n 网格 grid,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 输入:grid=[[1,3,1],[1,5,1],[4,2,1]] 输出:7 解释:因为路径1→3→1→1→1的总和最小。 对于每一块方块来说,只能从他的上边或者左边走过来,所以在for循环中

    2024年02月09日
    浏览(45)
  • 算法通关村第十二关-字符串基础题目

    思路:遍历字符串,将第i个字符和第N-i-1个字符串交换即可; 代码实现: 题目:反转字符串2 思路:每2k个一组,将其前k个字符反转,使用i+k与字符串长度n判断剩余字符串长度属于(0,k)还是 [k,2k)之间;然后按照要求剩余字符串即可; 代码实现: 题目:仅仅反转字母 思

    2024年01月22日
    浏览(48)
  • 算法通关村第十二关——字符串反转问题解析

    字符串反转是关于字符串算法里的重要问题,虽然不是太难,但需要考虑到一些边界问题。本篇文章就对几道字符串反转题目进行分析。 力扣344题,编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,

    2024年02月10日
    浏览(43)
  • 算法通关村第十八关:青铜挑战-回溯是怎么回事

    回溯,最重要的算法之一 主要解决一些暴力枚举也搞不定的问题,例如组合、分割、子集、排列、棋盘等 从性能角度来看回溯算法的效率并不高,但对于这些暴力都搞不定的算法能出结果就很好了,效率低点没关系 回溯可视为递归的拓展,很多思想和解法都与递归密切相关

    2024年02月09日
    浏览(41)
  • 算法通关村第十七关:青铜挑战-贪心其实很简单

    1. 难以解释的贪心算法 贪心学习法则:直接做题,不考虑贪不贪心 贪心(贪婪)算法 是指在问题尽心求解时,在每一步选择中都采取最好或者最优(最有利)的选择,从而希望能够导致结果最好或者最优的算法 贪心算法所得到的结果不一定是最优的结果,但是都是相对近似最

    2024年02月09日
    浏览(40)
  • 算法通关村第十六关——滑动窗口与堆结合

    LeetCode239给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位,返回滑动窗口中的最大值。 优先队列中每个值存储的是一个包含元素值和对应索引的数组 [元素值, 索引] 。在

    2024年02月11日
    浏览(45)
  • 算法通关村第十六关:青铜挑战-滑动窗口其实很简单

    1. 滑动窗口基本思想 数组引入双指针的背景: 很多算法会大量移动数组中的元素,频繁移动元素会导致执行效率低下或者超时,使用两个变量能比较好的解决很多相关问题 数组双指针,之前介绍过 对撞型 和 快慢型 两种,滑动窗口思想就是快慢型的特例 滑动窗口 示例:

    2024年02月09日
    浏览(43)
  • 算法通关村第十二关——不简单的字符串转换问题

    字符串是我们在日常开发中最常处理的数据,虽然它本身不是一种数据结构,但是由于其可以包含所有信息,所以通常作为数据的一种形式出现,由于不同语言创建和管理字符串的方式也各有差异,因此针对不同语言特征又产生了很多问题。 常见的字符串转换题目,也就是在

    2024年02月10日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包