这是我遇到的一个面试问题,我知道如何通过反复XORing数字来获得蛮力解决方案,但我不知道如何更有效地做到这一点。
我在businesscup上看到了这个解决方案:
typedef unsigned long long UINT64;
UINT64 getXOROne2N(UINT64 n) {
switch (n % 4) {
case 0: return n;
case 1: return 1;
case 2: return n + 1;
case 3: return 0;
}
return 0;
}
但即使有了这个人的解释,我也不完全理解这里的逻辑,有人可以解释一下如何做到这一点吗?
答案 0 :(得分:3)
当您查看n
的升序值的答案时,会出现一种数学模式。它看起来像一个四步旋转。这是因为我们在xoring奇数和偶数之间来回摆动,进入先前偶数和奇数结果的各种组合。每个连续的xor给我们带来四分之一的旋转。我将演示并解释。
让我们从头开始,n=1
:
00000001
请注意,这在解决方案中的case 1
范围内,返回的结果为1.另请注意,此n
的值为奇数,因此必须以1
结尾。< / p>
现在,当我们计算n=2
的解决方案时,它将成为前一个答案的解决方案,并使用n
的新值x:
00000001
^
00000010
--------
00000011
请注意,这属于解决方案的case 2
,其中返回的结果为n + 1
。另请注意,在这种情况下,n
是偶数,必须以0
结尾 - 所以当xored到前一个结果1(奇数)时,我们只是打开其他位,因此结果为任何类似的情况同样总是n+1
对于下一个值,getXOROne2N(3)
的结果自然是前一个结果,由3
得出。有趣的是,这将我们排除在零之外:
00000011
^
00000011
--------
00000000
当我们考虑它时,这是有道理的; getXOROne2N(2)
的结果是n+1 = 2+1 = 3
,因此当我们将(n+1
)的下一个值取消时,自然会将取消所有已签名的位返回到0。另请注意,这在您提供的解决方案中落入case 3
。
现在,只要我们在0之后计算下一个getXOROne2N
值,它就会是n
的下一个值 - 所以getXOROne2N(4)
是4。
00000000
^
00000100
--------
00000100
请注意,这在您提供的解决方案中整齐地落入case 0
。
现在,因为前一个0结果的4
是偶数,结果必然是尾随0.因此,xor到x的行中的下一个值必须具有此前一位配置但是当最后一位设置为1时,意味着当我们将它与先前的结果计算为getXOROne2N(5)
时,我们将取消除最后一位之外的所有位并返回到1:
00000100
^
00000101
--------
00000001
因此我们形成了轮换。在此之后的下一个将x输入偶数并因此产生n+1
(奇数),并且之后的下一个将取消回0
(以奇数编号以产生此偶数结果),然后我们将获得下一个n
(必须是偶数),然后在随后的奇数下一个值中向上xored将取消所有位,但最后一个仍保持打开,再次产生1。
这是一个恶性循环!但我觉得很漂亮。
答案 1 :(得分:2)
首先要注意的是,从可被4整除的数字开始的行中的任何4个数字如果异或,将导致0:
...00 - starting with any binary digits
...01
...10
...11
XOR -----
0 : 4 times (...), twice 1 for both lower digits
它实际上意味着只有在n
之前最大可被4整除后的最后一个数字才能形成实际结果(你可以在每个给出0的四边形中对所有数字进行分组)。
所以,它来了
%4 n calc result
0 ...00 -> ...00 = n
1 ...01 -> ...00 XOR ...01 = 1
2 ...10 -> ...10 XOR 1 = ...11 = n + 1
3 ...11 -> ...11 XOR ...11 = 0