我收到了这个面试问题:
给定一个具有 40 亿个整数的输入文件,提供一个算法来生成一个不包含在文件中的整数。假设您有 1 GB 内存。如果您只有 10 MB 的内存,请跟进您会做什么。
文件大小为 4×10 9 ×4 字节 = 16_GB。
我们可以进行外部排序,从而让我们知道整数的范围。
我的问题是在排序的大整数集中检测缺失整数的最佳方法是什么?
假设我们谈论的是 32 位整数,则有 2 32 = 4*10 9 个不同的整数。
如果我们使用一位代表一个不同的整数,就足够了。我们不需要排序。
int radix = 8; byte[] bitfield = new byte[0xffffffff/radix]; void F() throws FileNotFoundException{ Scanner in = new Scanner(new FileReader("a.txt")); while(in.hasNextInt()){ int n = in.nextInt(); bitfield[n/radix] |= (1 << (n%radix)); } for(int i = 0; i< bitfield.lenght; i++){ for(int j =0; j<radix; j++){ if( (bitfield[i] & (1<<j)) == 0) System.out.print(i*radix+j); } } }
解决方案: 对于所有可能的 16 位前缀,有 2 16个整数 = 65536,我们需要 2 16 * 4 * 8 = 2 百万位。我们需要构建 65536 个存储桶。对于每个桶,我们需要 4 个字节来保存所有可能性,因为最坏的情况是所有 40 亿个整数都属于同一个桶。 通过文件的第一次遍历构建每个桶的计数器。 扫描桶,找到第一个命中少于 65536 的桶。 构建新的存储桶,其高 16 位前缀是我们在第 2 步到文件的第二遍中找到的 扫描step3构建的bucket,找到第一个没有命中的bucket。 代码与上面的代码非常相似。
对于所有可能的 16 位前缀,有 2 16个整数 = 65536,我们需要 2 16 * 4 * 8 = 2 百万位。我们需要构建 65536 个存储桶。对于每个桶,我们需要 4 个字节来保存所有可能性,因为最坏的情况是所有 40 亿个整数都属于同一个桶。
代码与上面的代码非常相似。
结论:我们通过增加文件传递来减少内存。
对迟到的人的澄清:问题,正如所问的,并不是说文件中没有确切的一个整数——至少大多数人不是这样解释的。不过,评论线程中的许多评论 都是 关于该任务的变体。不幸的是,将其 引入 评论线程的评论后来被其作者删除,所以现在看起来对它的孤立回复只是误解了一切。非常混乱,抱歉。
假设“整数”表示 32 位 :10 MB 的空间足以让您计算输入文件中有多少具有任何给定 16 位前缀的数字,一次通过所有可能的 16 位前缀输入文件。至少有一个桶被击中少于 2 16次。执行第二遍以查找该存储桶中哪些可能的数字已被使用。
如果它意味着超过 32 位,但仍然是有界的大小 :按上述操作,忽略所有恰好落在(有符号或无符号;您的选择)32 位范围之外的输入数字。
如果“整数”表示数学整数 :通读一次输入并跟踪您见过的最长数的 最大数长度。 完成后,输出 最大值加 1 一个多位数的随机数。(文件中的一个数字可能是一个需要超过 10 MB 才能准确表示的 bignum,但如果输入是一个文件,那么您至少可以表示适合其中的任何内容的 长度)。