我的面试问题是这样的:

给定一个包含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.

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


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


当前回答

如果在[0,2 ^x - 1]范围内少了一个整数,那么就把它们一起xor。例如:

>>> 0 ^ 1 ^ 3
2
>>> 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 6 ^ 7
5

(我知道这并不能完全回答这个问题,但这是对一个非常相似的问题的一个很好的回答。)

其他回答

对于1gb RAM的变体,您可以使用位向量。你需要分配40亿比特== 500 MB字节数组。对于从输入中读取的每个数字,将相应的位设置为“1”。一旦你完成了,遍历比特,找到第一个仍然是“0”的比特。它的索引就是答案。

使用BitSet。40亿个整数(假设最多2^32个整数)以每字节8个的速度打包到BitSet中,大约是2^32 / 2^3 = 2^29 = 0.5 Gb。

要添加更多的细节-每次读取一个数字时,在BitSet中设置相应的位。然后,遍历BitSet以找到第一个不存在的数字。事实上,你可以通过重复选择一个随机数并测试它是否存在来有效地做到这一点。

实际上BitSet.nextClearBit(0)会告诉你第一个非设置位。

看看BitSet API,它似乎只支持0..MAX_INT,所以你可能需要2个bitset -一个用于+ ve数字,一个用于- ve数字-但内存需求不会改变。

给定一个包含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 时间~单次通过 完整性~是

我可能读得太仔细了,但问题是“生成一个不包含在文件中的整数”。我只是对列表进行排序,并在最大的条目上加1。Bam,一个没有包含在文件中的整数。

如果您不假设32位约束,则只返回一个随机生成的64位数字(如果您比较悲观,则返回128位数字)。碰撞的几率是1 / 2^64/(4*10^9)= 4611686018.4(大约40亿分之一)。大多数时候你都是对的!

(开玩笑的…种)。