问题:输入位于顺序文件中。该文件最多包含4亿个整数。找到缺失的整数。
根据我的理解解决方案:
制作两个临时文件,一个带前导0,另一个带前导1
两个MUST中的一个(4.3B鸽笼和4B鸽子)少于2B。 选择文件并重复步骤1& 2在第2位然后在第3位,依此类推......
这次迭代的最终条件是什么?
此外,该书提到算法的效率为O(n) 但是,
第1次迭代=> n探测操作
第二次迭代=> n / 2探头操作
。
。
。
n + n / 2 + n / 4 + ... 1 => nlogn ??
我错过了什么吗?
答案 0 :(得分:4)
您将检查这两个文件并选择具有最少元素的文件。
您将重复此过程,直到您完成所有32位,最后您将拥有0个元素的文件。这是其中一个缺失的数字应该是的地方。所以,如果你一直在跟踪你到目前为止已过滤的位数,你就会知道这个数字应该是多少。
请注意,这是为了找到 a (即“任意”)缺失的数字。如果给出一个(无序的)顺序列表40亿(不是2^32
(4294967296))整数,其中一个缺失,你必须找到,这将无法工作,因为你可以切断正确的缺失整数开始。
此外:
n + n/2 + n/4 + ... 1 <= 2n
不是n log n
。
这是geometric sequence a = n, r = 1/2
,可以使用以下公式计算:
n (1-(1/2)^m)
-------------
1 - (1/2)
由于0 < (1/2)^m < 1
代表任何正数m
(自0 < 1/2 < 1
起),我们可以说(1-r^m) < 1
,因此我们可以说最大值是:
n.1
-------
1 - 1/2
n
= ---
1/2
= 2n
答案 1 :(得分:2)
如果只有1个缺失值,则表示您具有以下条件:
N
到最高值M
的所有数字,除了其中一个数字。然后解决方案非常简单:
将文件中的所有数字一起添加或异或 将你应该拥有的所有数字加在一起或者异或 丢失的数字是一个减去另一个(在ADD的情况下)或一个x或另一个。
以下是您可以试用的LINQPad计划:
void Main()
{
var input = new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 };
var lowest = input[0];
var highest = input[0];
int xor = 0;
foreach (var value in input)
{
lowest = Math.Min(lowest, value);
highest = Math.Max(highest, value);
xor ^= value;
}
int requiredXor = 0;
for (int index = lowest; index <= highest; index++)
requiredXor ^= index;
var missing = xor ^ requiredXor;
missing.Dump();
}
基本上,它会:
此方法不会检测缺失值是否为最低值 - 1或最高值+ 1,例如,如果文件应该保持1..10但缺少10或1,则上述方法找不到它。
这个解决方案是O(2n)(我们将数字循环两次),转换为O(n)。
这是一个更完整的示例,显示了ADD和XOR解决方案(同样在LINQPad中):
void Main()
{
var input = new[] { 1, 2, 3, 4, 5, 6, 8, 9, 10 };
MissingXOR(input).Dump("xor");
MissingADD(input).Dump("add");
}
public static int MissingXOR(int[] input)
{
var lowest = input[0];
var highest = input[0];
int xor = 0;
foreach (var value in input)
{
lowest = Math.Min(lowest, value);
highest = Math.Max(highest, value);
xor ^= value;
}
int requiredXor = 0;
for (int index = lowest; index <= highest; index++)
requiredXor ^= index;
return xor ^ requiredXor;
}
public static int MissingADD(int[] input)
{
var lowest = input[0];
var highest = input[0];
int sum = 0;
foreach (var value in input)
{
lowest = Math.Min(lowest, value);
highest = Math.Max(highest, value);
sum += value;
}
var sumToHighest = (highest * (highest + 1)) / 2;
var sumToJustBelowLowest = (lowest * (lowest - 1)) / 2;
int requiredSum = sumToHighest - sumToJustBelowLowest;
return requiredSum - sum;
}