这个问题直接来自Cracking the Coding Interview, 4th Ed,所以我不是百分百肯定我可以在这里发布;如果没有,请告诉我,我会删除它。
问题5.7 :
数组A [1..n]包含从0到n的所有整数,除了一个 丢失的号码。在这个问题上,我们无法访问整个 A中的整数,只有一个操作。 A的元素是 以二进制表示,是我们可以用来访问的唯一操作 它们是“获取A [i]的第j位”,这需要恒定的时间。写 用于查找缺少的整数的代码。你能在O(n)时间内完成吗?
我知道如何解决这个问题。我不明白的是她如何解决它。她的方法:
当 n 的形式为(2 ^ m)-1 时,对于某些正 m ...我可以看到这种情况有效但是看不出它在一般情况下会如何起作用。
考虑二进制基数中的自然数。然后第i个最小sig位的序列如下:
然后,对于某些 s ,大多数sig位具有一些序列{(s)0(s)1}。如果 n =(2 ^ m)-1 ,那么一切都很好;对于每个量级,#1s =#0,因此我们可以使用作者逻辑。 但是,这在一般情况下如何运作?如果 n 是某个任意数字,则导致 n 的大多数sig位的序列如下所示:(s)0(s)1(s)0(s) 1 ...(k)1(显然序列必须以1作为大多数sig位结束), k 可以是[0,s]中的任何数字。那么她的逻辑如何应用? (最值得注意的是,第3步假设#0在通常情况下最多比#1更多1)
谢谢,如果有人能对此有所了解!谢谢!
答案 0 :(得分:9)
有三种可能性:
n
是奇数,因此0
位和1
位的数量应该相同。它们不会,所以较低的数字显然是缺失的数字。n
是偶数,因此0
位的数量应该比1
位的数量大1。如果它们相等,那就是缺少0
位。n
是偶数。如果0
位的数量比1
位的数量大2,则1
位是缺失的位。通过删除已删除的所有数字,您现在再次以递归方式应用完全相同的问题。
答案 1 :(得分:1)
我作为作业遇到了这个问题。尽管我知道讲师可能正在寻找更高级的东西,但我认为最简单的方法仍然可以在这里使用:即使您只能一点一点地访问整数,也可以在O(n) time
中计算其总和。准确地说,只需阅读32 * n bits
并进行数学计算即可。然后将您与n*(n+1)/2
进行比较,然后您就会知道答案。
我想在这里提及的一件事是
这实际上不是O(n)算法,否则称为线性算法。它实际上是一个伪线性,因为您需要n * W运算,其中W是所有整数的平均长度(除非问题明确指出,否则不要总是假设它们具有32位)。 W独立于n,因此不能完全证明它是线性算法。
答案 2 :(得分:-1)
更改前面提到的xor解决方案。 bit0 = XOR所有数字的bit0都是0到N的所有bit0的数组和XOR simillarly找到bit1到bit31。 然后结果是 bit0 | (bit1<< 1)...(bit31<< 31) 我已经编写了一个数字测试代码,可以使用最多3位写入。期待我的工作。此代码可以扩展为32位int。 如果这种方法有任何错误,请告诉我。感谢Poul在早期的解决中发现错误。
#include <stdio.h>
int main()
{
unsigned int a[7] = {0,6,2,3,4,5,1};
unsigned int bit0, bit1, bit2, missing,i;
bit0 = getbit(a[0], 0);
bit1 = getbit(a[0], 1);
bit2 = getbit(a[0], 2);
for (i=1 ; i <sizeof(a)/sizeof(unsigned int); i++)
{
bit0 ^= getbit(a[i],0) ;
bit1 ^= getbit(a[i],1);
bit2 ^= getbit(a[i],2);
}
for(i = 0; i <= sizeof(a)/sizeof(unsigned int); i++)
{
bit0 ^= getbit(i,0);
bit1 ^= getbit(i,1);
bit2 ^= getbit(i,2);
}
missing = bit0 | (bit1<<1) | bit2 << 2;
printf("%u\n",missing);
return 0;
}
int getbit(unsigned int x, unsigned int pos)
{
return ( (x & (1 << pos)) >> pos) ;
}