这是一个面试问题:
给定一个具有40亿个整数的输入文件,请提供一种算法来生成文件中不包含的整数。 假设您有1 GB的内存。 如果只有10 MB的内存,请执行后续操作。
我的分析:
文件大小为4×10 9 ×4字节= 16 GB。
我们可以进行外部排序,因此我们可以了解整数的范围。 我的问题是在已排序的大整数集中检测丢失的整数的最佳方法是什么?
我的理解(阅读所有答案后):
假设我们正在谈论32位整数。 有2 ^ 32 = 4 * 10 9个不同的整数。
情况1:我们有1 GB = 1 * 10 9 * 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);
}
}
}
情况2:10 MB内存= 10 * 10 6 * 8位= 8000万位
解决方案:对于所有可能的16位前缀,有2 ^ 16的整数数量= 65536,我们需要2 ^ 16 * 4 * 8 = 2百万个位。 我们需要构建65536个存储桶。 对于每个存储桶,我们需要4个字节来保存所有可能性,因为最坏的情况是所有40亿个整数都属于同一个存储桶。
- 通过第一次遍历文件来构建每个存储桶的计数器。
- 扫描存储桶,找到命中率小于65536的第一个。
- 通过在文件的第二遍中构建在步骤2中发现高16位前缀的新存储桶
- 扫描步骤3中内置的存储桶,找到第一个没有命中的存储桶。
该代码与上面的代码非常相似。
结论:我们通过增加文件传递来减少内存。
对于迟到者的说明:所问的问题不是说文件中没有正好包含一个整数-至少多数人不是这样解释的。 但是,注释线程中的许多注释都与任务的变化有关。 不幸的是, 将其引入注释线程的注释后来被其作者删除了,所以现在看来,孤立的答复似乎误解了所有内容。 这非常令人困惑。 抱歉。
#1楼
只要我们在做创造性的回答,这就是另一个。
使用外部排序程序对输入文件进行数字排序。 这将适用于您可能拥有的任何数量的内存(如果需要,它将使用文件存储)。 通读排序的文件并输出缺少的第一个数字。
#2楼
就像Ryan所说的那样,对文件进行排序,然后遍历整数,并在其中跳过一个值时就拥有它:)
编辑人士 :运营商提到可以对文件进行排序,因此这是一种有效的方法。
#3楼
使用一个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数字-但内存需求没有变化。
#4楼
对于1 GB RAM变量,可以使用位向量。 您需要分配40亿位== 500 MB字节数组。 对于从输入中读取的每个数字,将相应的位设置为“ 1”。 完成后,遍历位,找到第一个仍为“ 0”的位。 它的索引就是答案。
#5楼
您可以使用位标志来标记是否存在整数。
遍历整个文件后,扫描每一位以确定该数字是否存在。
假设每个整数都是32位,则如果完成位标记,它们将很方便地放入1 GB RAM中。
#6楼
假定“整数”表示32位 :拥有10 MB的空间已足够您计算带有给定16位前缀的输入文件中有多少个数字,一次通过所有可能的16位前缀输入文件。 至少有一个水桶命中率低于2 ^ 16次。 再进行一遍,以查找该存储桶中哪些可能的数字已被使用。
如果它意味着超过32位,但仍为有界大小 :请执行上述操作,忽略所有恰好超出(有符号或无符号;您选择的)32位范围的所有输入数字。
如果“ integer”表示数学整数 :请仔细阅读一次输入,并跟踪您所见过的最长数字中的最大数字长度。 完成后,输出最大值加一 , 再加上一个具有一位数字的随机数。 (文件中的一个数字可能是一个大于10 MB的数字,要精确表示,但是如果输入是文件,则至少可以表示适合该文件的长度 )。
#7楼
最简单的方法是在文件中找到最小数目,然后返回最小数目。 这将使用O(1)存储和n个文件的O(n)时间。 但是,如果数字范围受到限制,它将失败,这可能会使min-1不是数字。
已经提到了使用位图的简单明了的方法。 该方法使用O(n)时间和存储空间。
还提到了具有2 ^ 16个计数桶的2遍方法。 它读取2 * n个整数,因此使用O(n)时间和O(1)存储,但是它不能处理具有2 ^ 16以上数字的数据集。 但是,通过运行4次而不是2次,它很容易扩展到(例如)2 ^ 60个64位整数,并且通过仅使用与内存匹配的尽可能多的bin并相应地增加通过次数,就很容易适应使用微型内存。在这种情况下,运行时间不再是O(n),而是O(n * log n)。
到目前为止,rfrankel和ircmaxell都提到了对所有数字进行异或运算的方法,这回答了ltn100所指出的stackoverflow#35185中提出的问题。 它使用O(1)存储和O(n)运行时间。 如果目前假设32位整数,则XOR产生不同数字的概率为7%。 理由:给定约4G的不同数字XOR的总和。 300M不在文件中,每个位位置的置1位数具有相等的奇数或偶数机会。 因此,有2 ^ 32个数字具有作为XOR结果的同等可能性,其中93%已经归档。 请注意,如果文件中的数字不是全部不同,则XOR方法成功的可能性会增加。
#8楼
技巧问题,除非被引用不正确。 只需读取文件一次即可获得最大整数n
,并返回n+1
。
当然,如果n+1
导致整数溢出,您将需要一个备份计划。
#9楼
对于10 MB的内存限制:
- 将数字转换为其二进制表示形式。
- 创建一个二叉树,其中left = 0和right = 1。
- 使用其二进制表示形式将每个数字插入树中。
- 如果已经插入数字,则将已经创建了叶子。
完成后,只需采用之前未创建的路径即可创建请求的号码。
40亿个数字= 2 ^ 32,意味着10 MB可能不够。
编辑
有可能进行优化,如果创建了两个末端叶子并具有一个公共父叶,则可以将它们删除,并将父叶标记为不是解决方案。 这样可以减少分支并减少对内存的需求。
编辑二
也无需完全构建树。 如果数字相似,则只需要建立深分支。 如果我们也削减分支,那么该解决方案实际上可能会起作用。
#10楼
编辑好的,这还没有经过深思熟虑,因为它假定文件中的整数遵循某种静态分布。 显然他们并不需要,但是即使如此,也应该尝试这样做:
共有约43亿个32位整数。 我们不知道它们在文件中的分布方式,但是最坏的情况是香农熵最高的情况:均等分布。 在这种情况下,文件中不出现任何一个整数的概率为
((2³²-1)/2³²)⁴⁰⁰⁰≈.4
香农熵越低,则平均获得该概率越高,但是即使在这种最坏的情况下,我们也有90%的机会在经过5次随机整数猜测后找到了一个不出现的数字。 只需使用伪随机数生成器创建此类数字,然后将其存储在列表中即可。 然后在int之后读取int并将其与您的所有猜测进行比较。 匹配时,删除此列表条目。 浏览完所有文件后,您可能还剩下一个以上的猜测。 使用其中任何一个。 在几乎没有猜测的罕见(即使在最坏的情况下为10%)事件中,获取一组新的随机整数,这次可能更多(10-> 99%)。
内存消耗:几十个字节,复杂度:O(n),开销:可忽略不计,因为大多数时间将花费在不可避免的硬盘访问上,而不是始终比较整数。
当我们 不假设静态分布时,实际最坏的情况是每个整数都出现最大值。 一次,因为这样文件中就不会出现所有整数的1-4000000000 /2³²≈6%。 因此,您还需要更多猜测,但这仍然不会浪费大量内存。
#11楼
根据原始问题的当前措辞,最简单的解决方案是:
在文件中找到最大值,然后将其加1。
#12楼
有关此问题的详细讨论,已在Jon Bentley的 “专栏1:裂解牡蛎”中进行了编程Pearls Addison-Wesley pp.3-10
Bentley讨论了几种方法,包括外部排序,使用多个外部文件进行合并排序等。但是Bentley建议的最佳方法是使用位字段的单次通过算法,他幽默地称其为“ Wonder Sort” :)来解决这个问题,有40亿数字可以表示为:
4 billion bits = (4000000000 / 8) bytes = about 0.466 GB
实现位集的代码很简单:(摘自解决方案页面 )
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1 + N/BITSPERWORD];
void set(int i) { a[i>>SHIFT] |= (1<<(i & MASK)); }
void clr(int i) { a[i>>SHIFT] &= ~(1<<(i & MASK)); }
int test(int i){ return a[i>>SHIFT] & (1<<(i & MASK)); }
Bentley算法对文件进行一次遍历, set
数组中的适当位,然后使用上面的test
宏检查该数组以查找丢失的数字。
如果可用内存小于0.466 GB,Bentley建议使用k-pass算法,该算法会根据可用内存将输入划分为多个范围。 举一个非常简单的例子,如果只有1个字节(即用于处理8个数字的内存)可用并且范围从0到31,我们将其划分为0到7、8-15、16-22等范围。并以32/8 = 4
遍中的每32/8 = 4
处理此范围。
HTH。
#13楼
统计确定的算法比确定性方法使用更少的遍数来解决此问题。
如果允许使用非常大的整数,则可以生成一个在O(1)时间内可能唯一的数字。 像GUID这样的伪随机128位整数将仅与集合中现有的40亿个整数之一发生冲突,而不会发生于每640亿亿个案例中的十分之一。
如果整数限制为32位,则可以使用一次少于10 MB的数据生成一个唯一可能唯一的数字。 伪随机的32位整数将与40亿个现有整数之一发生冲突的几率约为93%(4e9 / 2 ^ 32)。 1000个伪随机整数全部发生碰撞的几率小于12,000万亿的整数(一次碰撞的可能性^ 1000)。 因此,如果程序维护一个包含1000个伪随机候选者的数据结构并迭代已知的整数,从而消除候选者中的匹配项,则几乎可以肯定找到了文件中没有的至少一个整数。
#14楼
如果它们是32位整数(可能是从大约40个数字中选择接近2 32的数字),则40亿个数字列表将最多占据93%的可能整数(4 * 10 9 /(2 32 ) )。 因此,如果您创建一个2 32位的位数组,并且每个位都初始化为零(这将占用2 29个字节〜500 MB的RAM;记住一个字节= 2 3位= 8位),请通读整数列表并对于每个int,将相应的位数组元素设置为0到1; 然后读取您的位数组并返回仍然为0的第一位。
如果您的RAM较少(〜10 MB),则需要对该解决方案进行一些修改。 10 MB〜83886080位仍然足以对0到83886079之间的所有数字进行位数组处理。因此,您可以通读int列表; 并且仅在您的位阵列中记录0到83886079之间的#号。 如果数字是随机分布的; 出现压倒性的可能性(相差100%大约10 -2592069 ),您会发现缺少一个整数。 实际上,如果您仅选择数字1至2048(仅具有256个字节的RAM),那么您仍然会发现丢失的数字占了绝大多数(99.999999999999999999999999999999999999999999999999995%)。
但是,可以说不是拥有大约40亿个数字; 您有类似2 32-1的数字和少于10 MB的RAM; 因此,任何小范围的整数都只有很小的可能性不包含数字。
如果你是保证每一个列表中的诠释是独一无二的,你可以总结数字和减去一个#缺少完整的总和(1/2)(2 32)(2 32 - 1)的总和= 9223372034707292160寻找失踪的INT 。 但是,如果int发生两次,则此方法将失败。
但是,您始终可以分而治之。 天真的方法是读取数组并计算上半部分(0到2 31 -1)和下半部分(2 31,232 )中的数字数量。 然后选择数量较少的范围,然后重复将该范围二等分。 (假设如果(2 31,232 )中的数字少两个,则下一次搜索将计算(2 31,3 * 2 30 -1),(3 * 2 30,232 )范围内的数字。重复进行操作,直到找到一个范围为零的数字,然后得到答案为止,应进行O(lg N)〜32次读取数组的操作。
该方法效率低下。 我们在每个步骤中仅使用两个整数(或大约8个字节的RAM和一个4字节(32位)的整数)。 更好的方法是将sqrt(2 32 )= 2 16 = 65536个bin划分为每个bin中的65536个数字。 每个bin需要4个字节来存储其计数,因此您需要2个18个字节= 256 kB。 所以bin 0是(0到65535 = 2 16 -1),bin 1是(2 16 = 65536到2 * 2 16 -1 = 131071),bin 2是(2 * 2 16 = 131072到3 * 2 16- 1 = 196607)。 在python中,您会有类似以下内容:
import numpy as np
nums_in_bin = np.zeros(65536, dtype=np.uint32)
for N in four_billion_int_array:
nums_in_bin[N // 65536] += 1
for bin_num, bin_count in enumerate(nums_in_bin):
if bin_count < 65536:
break # we have found an incomplete bin with missing ints (bin_num)
仔细阅读约40亿个整数列表; 并计算在2 个16个 bin中的每个中有多少个int,并找到一个不完整的65536个数字的incomplete_bin。 然后,您再次通读40亿个整数列表; 但这一次只注意整数在该范围内; 找到它们时会翻转一下。
del nums_in_bin # allow gc to free old 256kB array
from bitarray import bitarray
my_bit_array = bitarray(65536) # 32 kB
my_bit_array.setall(0)
for N in four_billion_int_array:
if N // 65536 == bin_num:
my_bit_array[N % 65536] = 1
for i, bit in enumerate(my_bit_array):
if not bit:
print bin_num*65536 + i
break
#15楼
由于问题未指明我们必须找到文件中没有的最小可能数字,因此我们可以生成比输入文件本身更长的数字。 :)
#16楼
消除位
一种方法是消除位,但是这实际上可能不会产生结果(可能不会)。 伪代码:
long val = 0xFFFFFFFFFFFFFFFF; // (all bits set)
foreach long fileVal in file
{
val = val & ~fileVal;
if (val == 0) error;
}
位计数
跟踪位数; 并使用数量最少的位生成值。 同样,这不能保证产生正确的值。
范围逻辑
跟踪列表的排序范围(按开始排序)。 范围由以下结构定义:
struct Range
{
long Start, End; // Inclusive.
}
Range startRange = new Range { Start = 0x0, End = 0xFFFFFFFFFFFFFFFF };
浏览文件中的每个值,然后尝试将其从当前范围中删除。 此方法没有内存保证,但应该做得很好。
#17楼
我将回答1 GB版本:
问题中没有足够的信息,因此我将首先陈述一些假设:
整数是32位,范围为-2,147,483,648至2,147,483,647。
伪代码:
var bitArray = new bit[4294967296]; // 0.5 GB, initialized to all 0s.
foreach (var number in file) {
bitArray[number + 2147483648] = 1; // Shift all numbers so they start at 0.
}
for (var i = 0; i < 4294967296; i++) {
if (bitArray[i] == 0) {
return i - 2147483648;
}
}
#18楼
为什么要这么复杂? 您要求文件中不存在整数?
根据指定的规则,您唯一需要存储的是文件中到目前为止遇到的最大整数。 读取完整个文件后,返回大于1的数字。
没有命中maxint或任何东西的风险,因为根据规则,对整数的大小或算法返回的数字没有限制。
#19楼
使用二进制搜索的变体可以解决这一问题。
从允许的数字范围
0
到4294967295
。计算中点。
遍历文件,计算等于或小于中点值的数字个数。
如果没有数字相等,那么就完成了。 中点数字就是答案。
否则,请选择编号最少的范围,并使用新范围从步骤2开始重复。
这将需要整个文件进行32次线性扫描,但是它将仅使用几个字节的内存来存储范围和计数。
这与Henning的解决方案基本相同,除了它使用两个垃圾箱而不是16k。
#20楼
他们可能想看看您是否听说过概率布隆过滤器 ,该过滤器可以非常有效地绝对确定某个值是否不属于大型集合(但只能以很高的概率确定该值是否属于该集合)。
#21楼
如果在[0,2 ^ x -1]范围内缺少一个整数,则将它们全部异或。 例如:
>>> 0 ^ 1 ^ 3
2
>>> 0 ^ 1 ^ 2 ^ 3 ^ 4 ^ 6 ^ 7
5
(我知道这并不能完全回答问题,但这是对非常相似的问题的很好的回答。)
#22楼
检查输入文件的大小,然后输出任何 太大而无法用该大小的文件表示的数字。 这看似便宜,但它是解决面试问题的创造性方法,它巧妙地避开了内存问题,从技术上讲是O(n)。
void maxNum(ulong filesize)
{
ulong bitcount = filesize * 8; //number of bits in file
for (ulong i = 0; i < bitcount; i++)
{
Console.Write(9);
}
}
应该打印10位计数 -1 ,它将始终大于2位计数 。 从技术上讲,你必须击败数为2 位计数 - (4 * 十月九日至一日),因为你知道有(4十亿- 1)以外的整数中的文件,甚至与完美的压缩,他们至少会占用每个一位。
#23楼
如果没有大小限制,最快的方法是获取文件的长度,并生成文件的长度+ 1个随机数字(或仅为“ 11111 ...” s)。 优点:您甚至不需要读取文件,并且可以将内存使用率降至几乎为零。 缺点:您将打印数十亿个数字。
但是,如果唯一的因素是最大程度地减少内存使用,并且没有其他重要意义,那将是最佳解决方案。 它甚至可能使您获得“最糟糕的规则滥用”奖。
#24楼
如果您不采用32位约束,则只需返回一个随机生成的64位数字(如果您是悲观主义者,则返回128位)。 发生碰撞的几率是1 in 2^64/(4*10^9) = 4611686018.4
(大约40亿分之一)。 您大多数时候都是对的!
(开玩笑……有点。)
#25楼
2 128 * 10 18 +1(即(2 8 ) 16 * 10 18 +1)-今天不能成为一个普遍的答案吗? 这表示不能保存在16 EB文件中的数字,这是任何当前文件系统中的最大文件大小。
#26楼
我认为这是一个已解决的问题(请参见上文),但请牢记一个有趣的附带情况,因为可能会被问到:
如果正好有4,294,967,295(2 ^ 32-1)个32位整数没有重复,因此仅缺少一个整数,则有一个简单的解决方案。
从零开始运行总计,然后为文件中的每个整数添加32位溢出的整数(有效地,runningTotal =(runningTotal + nextInteger)%4294967296)。 完成后,将4294967296/2添加到运行总计中,再次出现32位溢出。 从4294967296减去它,结果是缺少的整数。
仅运行一次即可解决“只有一个丢失的整数”问题,并且只有64位专用于数据的RAM(运行的总数为32位,下一个整数为32位)。
结论:如果我们不关心整数结果必须具有多少位,则更通用的规范非常容易匹配。 我们只是生成了一个足够大的整数,该整数不能包含在给出的文件中。 同样,这会占用绝对最少的RAM。 参见伪代码。
# Grab the file size
fseek(fp, 0L, SEEK_END);
sz = ftell(fp);
# Print a '2' for every bit of the file.
for (c=0; c<sz; c++) {
for (b=0; b<4; b++) {
print "2";
}
}
#27楼
仅出于完整性考虑,这是另一个非常简单的解决方案,很可能需要很长时间才能运行,但占用的内存却很少。
令所有可能的整数为从int_min
到int_max
的范围,并且bool isNotInFile(integer)
一个函数,如果文件不包含某个整数,则返回true,否则返回false(通过将该特定整数与文件中的每个整数进行比较)
for (integer i = int_min; i <= int_max; ++i)
{
if (isNotInFile(i)) {
return i;
}
}
#28楼
从文件中删除空格和非数字字符,然后追加1。您的文件现在包含一个未在原始文件中列出的数字。
从Carbonetc的Reddit。
#29楼
如果我们假设数字范围始终为2 ^ n(2的偶数次幂),则“异或”将起作用(如另一幅海报所示)。 至于为什么,让我们证明一下:
理论
给定具有2^n
元素且缺少一个元素的任何从0开始的整数范围,您可以通过简单地将已知值异或在一起以得出缺失的数字来找到该缺失的元素。
证据
让我们看一下n =2。对于n = 2,我们可以表示4个唯一整数:0、1、2、3。它们的位模式为:
- 0-00
- 1-01
- 2-10
- 3-11
现在,如果我们看的话,每一位都精确地设置了两次。 因此,由于将其设置为偶数,并且数字的“异或”运算将产生0。如果缺少单个数字,则“异或”将生成一个数字,当与缺失的数字进行异或运算时将导致: 0。因此,丢失的数字和所得的异或数字完全相同。 如果我们删除2,则结果xor将为10
(或2)。
现在,让我们看一下n + 1。 我们将每个位设置为n
, x
的次数,将每个位设置为n+1
y
。 y
的值等于y = x * 2
因为存在x
元素的n+1
位设置为0, x
元素的n+1
位设置为1。由于2x
始终为偶数,因此n+1
总是将每个位设置为偶数次。
因此,由于n=2
有效且n+1
有效,因此xor方法将对n>=2
所有值有效。
基于0的范围的算法
这很简单。 它使用2 * n位的内存,因此对于<= 32的任何范围,将使用2个32位整数(忽略文件描述符消耗的任何内存)。 它使文件一次通过。
long supplied = 0;
long result = 0;
while (supplied = read_int_from_file()) {
result = result ^ supplied;
}
return result;
基于任意距离的算法
只要总范围等于2 ^ n,该算法就可以适用于任何起始数字到任何终止数字的范围...这基本上是重新确定范围的最小范围为0。但是它确实需要2次通过通过文件(第一个获取最小值,第二个计算缺失的int)。
long supplied = 0;
long result = 0;
long offset = INT_MAX;
while (supplied = read_int_from_file()) {
if (supplied < offset) {
offset = supplied;
}
}
reset_file_pointer();
while (supplied = read_int_from_file()) {
result = result ^ (supplied - offset);
}
return result + offset;
任意范围
我们可以将此修改后的方法应用于一组任意范围,因为所有范围都将至少一次穿越2 ^ n的幂。 仅在缺少单个位时有效。 它需要2次传递未排序的文件,但是每次都会找到一个丢失的数字:
long supplied = 0;
long result = 0;
long offset = INT_MAX;
long n = 0;
double temp;
while (supplied = read_int_from_file()) {
if (supplied < offset) {
offset = supplied;
}
}
reset_file_pointer();
while (supplied = read_int_from_file()) {
n++;
result = result ^ (supplied - offset);
}
// We need to increment n one value so that we take care of the missing
// int value
n++
while (n == 1 || 0 != (n & (n - 1))) {
result = result ^ (n++);
}
return result + offset;
基本上,将范围重新设在0附近。然后,在计算异或时,它会计算要附加的未排序值的数量。 然后,它将未排序的值的计数加1以处理缺失的值(计算缺失的值)。 然后,继续对n值进行异或运算,每次将其递增1,直到n为2的幂为止。然后将结果重新基于原始值。 完成。
这是我在PHP中测试的算法(使用数组而不是文件,但概念相同):
function find($array) {
$offset = min($array);
$n = 0;
$result = 0;
foreach ($array as $value) {
$result = $result ^ ($value - $offset);
$n++;
}
$n++; // This takes care of the missing value
while ($n == 1 || 0 != ($n & ($n - 1))) {
$result = $result ^ ($n++);
}
return $result + $offset;
}
以任意范围的值(我测试过包括否定值)将数组放入其中,而该范围内缺少一个值,则每次都会找到正确的值。
另一种方法
既然我们可以使用外部排序,为什么不检查差距呢? 如果我们假设文件在运行此算法之前已排序:
long supplied = 0;
long last = read_int_from_file();
while (supplied = read_int_from_file()) {
if (supplied != last + 1) {
return last + 1;
}
last = supplied;
}
// The range is contiguous, so what do we do here? Let's return last + 1:
return last + 1;
#30楼
由于某种原因,我一读到这个问题就想到了对角化。 我假设任意大的整数。
阅读第一个数字。 左填充零位,直到有40亿位。 如果第一个(高阶)位为0,则输出1;否则为0。 否则输出0。(不必真正按左移键:如果数字中的位数不足,只需输出1。)对第二个数字执行相同的操作,除了使用第二个数字。 以这种方式继续浏览文件。 您将一次输出一个40亿位数字,该数字将与文件中的任何数字都不相同。 证明:它与第n个数字相同,然后他们会在第n个比特上达成共识,但并非出于构造目的。