我的面试问题是这样的:

给定一个包含40亿个整数的输入文件,提供一种算法来生成一个文件中不包含的整数。假设您有1gb内存。如果你只有10mb的内存,你会怎么做。

我的分析:

文件大小为4×109×4 bytes = 16gb。

我们可以进行外部排序,从而知道整数的范围。

我的问题是,在已排序的大整数集中检测缺失整数的最佳方法是什么?

我的理解(看完所有答案后):

假设我们讨论的是32位整数,有232 = 4*109个不同的整数。

情况1:我们有1gb = 1 * 109 * 8位= 80亿位内存。

解决方案:

如果我们用一位表示一个不同的整数,这就足够了。我们不需要排序。

实现:

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);
        }
    }
}

情形二:10mb内存= 10 * 106 * 8bits = 8000万bits

Solution: For all possible 16-bit prefixes, there are 216 number of integers = 65536, we need 216 * 4 * 8 = 2 million bits. We need build 65536 buckets. For each bucket, we need 4 bytes holding all possibilities because the worst case is all the 4 billion integers belong to the same bucket. Build the counter of each bucket through the first pass through the file. Scan the buckets, find the first one who has less than 65536 hit. Build new buckets whose high 16-bit prefixes are we found in step2 through second pass of the file Scan the buckets built in step3, find the first bucket which doesnt have a hit. The code is very similar to above one.

结论: 我们通过增加文件传递来减少内存。


为那些迟到的人澄清一下:这个问题,正如所问的,并不是说有一个整数没有包含在文件中——至少大多数人不是这么理解的。不过,评论线程中的许多评论都是关于任务的变化。不幸的是,把它引入评论线程的评论后来被它的作者删除了,所以现在看起来它的孤儿回复只是误解了一切。这很让人困惑,抱歉。


当前回答

为什么要把它弄得这么复杂?你要的是一个文件中没有的整数?

根据指定的规则,您唯一需要存储的是到目前为止在文件中遇到的最大整数。读取整个文件后,返回一个大于1的数字。

不存在触及maxint或任何东西的风险,因为根据规则,对算法返回的整数或数字的大小没有限制。

其他回答

Surely, and speaking with limited experience (just started learning java at Uni) you can run trhough one set (barrel) of int, and if number not found dispose of barrel. This would both free up space and run a check through each unit of data. If what you are looking for is found add it to a count variable. Would take a long time but, if you made multiple variables for each section and run the check count through each variable and ensure they are exiting/disposing at the same time, the variable storage should not increase? And will speed up the check process. Just a thought.

如果没有大小限制,最快的方法是取文件的长度,并生成文件的长度+1个随机数字(或者只是“11111…”s).优点:您甚至不需要读取文件,并且可以将内存使用最小化到几乎为零。缺点:将打印数十亿个数字。

但是,如果唯一的因素是最小化内存使用,而其他因素都不重要,那么这将是最佳解决方案。它甚至可能让你获得“最严重滥用规则”奖。

既然我们在做创造性的回答,下面是另一个问题。

使用外部排序程序对输入文件进行数字排序。这将适用于任何数量的内存(如果需要,它将使用文件存储)。 通读排序文件并输出缺少的第一个数字。

给定一个包含40亿个整数的输入文件,提供一个算法 生成文件中不包含的整数。假设你 有1gib的内存。接着问如果只有你会怎么做 10内存MiB。 文件大小为4 * 109 * 4字节= 16gib

如果是32位无符号整数

0 <= Number < 2^32
0 <= Number < 4,294,967,296

我建议的解决方案是:c++不进行错误检查

#include <vector>
#include <fstream>
#include <iostream>
using namespace std;

int main ()
{
    const long SIZE = 1L << 32;

    std::vector<bool> checker(SIZE, false);

    std::ifstream infile("file.txt");  // TODO: error checking

    unsigned int num = 0;

    while (infile >> num)
    {
        checker[num] = true ;
    }

    infile.close();

    // print missing numbers

    for (long i = 0; i < SIZE; i++)
    {
        if (!checker[i])
            cout << i << endl ;
    }

    return 0;
}

复杂性

Space ~ 232 bits = 229 Bytes = 219 KB = 29 MB = 1/2 GB 时间~单次通过 完整性~是

我想出了下面的算法。

我的想法是:遍历整个整数文件一次,对每个位位置数0和1。0和1的数量必须是2^(numOfBits)/2,因此,如果数量比预期的少,我们可以使用我们的结果数。

例如,假设整数是32位,那么我们需要

int[] ones = new int[32];
int[] zeroes = new int[32];

对于每个数字,我们必须迭代32位,并增加0或1的值:

for(int i = 0; i < 32; i++){
   ones[i] += (val>>i&0x1); 
   zeroes[i] += (val>>i&0x1)==1?0:1;
}

最后,在文件处理后:

int res = 0;
for(int i = 0; i < 32; i++){
   if(ones[i] < (long)1<<31)res|=1<<i;
}
return res;

注意:在某些语言中(如Java) 1<<31是负数,因此,(长)1<<31是正确的方法