查找所有数字的XOR在给定的范围

问题描述 投票:91回答:5

您将得到一个大范围的[A,B],其中“a”和“B”可以是通常为1至40亿(含)之间。你必须找出在给定范围内的所有数字的XOR。

在TopCoder公司SRM使用此问题。我看到在比赛中提交的解决方案之一,我无法弄清楚如何其工作。

有人能帮助解释成功的解决方案:

long long f(long long a) {
     long long res[] = {a,1,a+1,0};
     return res[a%4];
}

long long getXor(long long a, long long b) {
     return f(b)^f(a-1);
}

这里,getXor()是计算在通过范围[A,B]和“f()”的所有数的异或的实际功能是一个辅助功能。

algorithm
5个回答
141
投票

这是一个非常聪明的解决方案 - 它利用这样的事实,有结果的异或运行的模式。所述f()函数计算从[0,A]的XOR总运行。看看这个表4位数字:

0000 <- 0  [a]
0001 <- 1  [1]
0010 <- 3  [a+1]
0011 <- 0  [0]
0100 <- 4  [a]
0101 <- 1  [1]
0110 <- 7  [a+1]
0111 <- 0  [0]
1000 <- 8  [a]
1001 <- 1  [1]
1010 <- 11 [a+1]
1011 <- 0  [0]
1100 <- 12 [a]
1101 <- 1  [1]
1110 <- 15 [a+1]
1111 <- 0  [0]

其中第一列是二进制表示,然后将小数结果及其与它的指标的(a)到XOR列表。这是因为所有的高位取消,最低的两位周期每隔4所以,这就是如何在这个小查找表到达。

现在,考虑的一般范围为[A,B]。我们可以用f()找到了XOR [0,A-1]和[0,B]。由于与自身进行XOR运算,任何值为零,f(a-1)正好抵消在XOR中的所有值运行不到a,让你与范围的XOR [A,B]。


52
投票

添加到FatalError的伟大答案,行return f(b)^f(a-1);可以解释的更好。总之,这是因为XOR有这些奇妙的特性:

  • 这是联想 - 放置支架,无论你想
  • 它的交换 - 这意味着你可以随意移动运营商(他们可以“下班”)

这里有两个在行动:

(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
  • 它本身反转

像这样:

a ^ b = c
c ^ a = b

添加和乘其他关联/可交换操作的两个例子,但他们不扭转自己。好了,那么,为什么这些特性很重要?那么,一个简单的途径是扩大它到它到底是什么,然后就可以看到这些属性在起作用。

首先,让我们来定义我们想要的和正调用它:

n      = (a ^ a+1 ^ a+2 .. ^ b)

如果有帮助,认为XOR(^),就好像它是一个补充。

我们还定义函数:

f(b)   = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b

ba更大,所以只是通过一些额外的支架安全下降(我们不能因为它的关联),我们也可以这样说:

f(b)   = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)

这简化为:

f(b)   = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)

f(b)   = f(a-1) ^ n

接下来,我们使用的是反转性质和commutivity给予我们的魔线:

n      = f(b) ^ f(a-1)

如果你一直喜欢一个附加思维XOR,你会一直在那里减去下降。 XOR是异或什么补充的是减去!

How do I come up with this myself?

记住逻辑运算的性能。与他们的工作就像一个相加或相乘,如果有帮助。这种感觉不同寻常,和(),XOR(^)和或(|)是关联的,但他们!

通过先运行幼稚的做法,寻找在输出模式,然后开始寻找其确认该模式是真正的规则。进一步简化您的实现和重复。这可能是原创者所走的路线,通过一个事实,即它不是完全最佳高亮(即使用switch语句,而不是一个数组)。


3
投票

我发现下面的代码也在努力像这个问题给出的解决方案。

可能是这一点优化,但它只是我从观察重复像接受的答案给出了,

我想知道/了解给定的代码背后的数学证明,如由@Luke布里格斯答案解释

这里是一个JAVA代码

public int findXORofRange(int m, int n) {
    int[] patternTracker;

    if(m % 2 == 0)
        patternTracker = new int[] {n, 1, n^1, 0};
    else
        patternTracker = new int[] {m, m^n, m-1, (m-1)^n};

    return patternTracker[(n-m) % 4];
}

0
投票

我已经解决了递归问题。我简单地划分成集几乎相等的一部分,每次迭代。

public int recursion(int M, int N) {
    if (N - M == 1) {
        return M ^ N;
    } else {
        int pivot = this.calculatePivot(M, N);
        if (pivot + 1 == N) {
            return this.recursion(M, pivot) ^ N;
        } else {
            return this.recursion(M, pivot) ^ this.recursion(pivot + 1, N);
        }
    }
}
public int calculatePivot(int M, int N) {
    return (M + N) / 2;
}

让我知道在解决你的看法。高兴得到改进的反馈。提出的解决方案计算出0(日志N)复杂XOR。

谢谢


0
投票

为了支持XOR从0到N给定所需的代码作如下修改,

int f(int a) {
    int []res = {a, 1, a+1, 0};
    return res[a % 4];
}

int getXor(int a, int b) {
    return f(b) ^ f(a);
}
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.