对于给定的n,如何从1..n中取出数字的xor? (例如1 ^ 2 ^ 3 ^ ... ^ n)?

时间:2015-11-14 06:28:07

标签: algorithm bit-manipulation xor bitwise-xor

这是我遇到的一个面试问题,我知道如何通过反复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;
}

但即使有了这个人的解释,我也不完全理解这里的逻辑,有人可以解释一下如何做到这一点吗?

2 个答案:

答案 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