Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 查找给定范围内所有数字的异或_Algorithm - Fatal编程技术网

Algorithm 查找给定范围内所有数字的异或

Algorithm 查找给定范围内所有数字的异或,algorithm,Algorithm,您会得到一个大范围[a,b],其中“a”和“b”通常介于1和4000000000之间(包括1和4000000000)。你必须找出给定范围内所有数字的异或 这个问题被用于TopCoder SRM。我在比赛中看到了一个提交的解决方案,我不知道它是如何工作的 有人能解释一下获胜的解决方案吗: 长f(长a){ long-long-res[]={a,1,a+1,0}; 返回res[a%4]; } long-long getXor(long-long a,long-long b){ 申报表f(b)^f(a-

您会得到一个大范围[a,b],其中“a”和“b”通常介于1和4000000000之间(包括1和4000000000)。你必须找出给定范围内所有数字的异或

这个问题被用于TopCoder SRM。我在比赛中看到了一个提交的解决方案,我不知道它是如何工作的

有人能解释一下获胜的解决方案吗:

长f(长a){
long-long-res[]={a,1,a+1,0};
返回res[a%4];
}
long-long getXor(long-long a,long-long b){
申报表f(b)^f(a-1);
}

这里,
getXor()
是计算传递范围[a,b]中所有数字的xor的实际函数,“f()”是一个辅助函数。

这是一个非常聪明的解决方案——它利用了在运行xor时存在结果模式这一事实。
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]

0000在法塔莱罗的伟大答案的基础上增加了一行
返回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:

n      = (a ^ a+1 ^ a+2 .. ^ b)
如果有帮助,可以将XOR(^)看作是一个add

我们还要定义函数:

f(b)   = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b
b
大于
a
,因此只需安全地放入几个额外的括号(我们可以这样做,因为它是关联的),我们也可以这样说:

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
接下来,我们利用反转性质和可换性给出了幻线:

n      = f(b) ^ f(a-1)
如果你一直把异或看作是加法,那么你就会在那里加入减法。XOR之于XOR,就像加法之于减法一样

我自己是怎么想到这个的? 记住逻辑运算符的属性。如果有帮助的话,可以像加法或乘法一样处理它们。and(&)、xor(^)和or(|)是关联的,这感觉很不寻常,但它们是关联的


首先运行naive实现,在输出中查找模式,然后开始查找确认模式为真的规则。进一步简化您的实现并重复。这可能是原始创建者采取的路线,突出的是它不是完全最优的(即使用switch语句而不是数组)。

我发现下面的代码也与问题中给出的解决方案一样工作

也许这有点优化,但这正是我从观察重复中得到的,就像在接受的答案中给出的一样

我想知道/理解给定代码背后的数学证明,就像@Luke Briggs在回答中解释的那样

这是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];
}

我已经用递归解决了这个问题。对于每次迭代,我只是将数据集分成几乎相等的部分

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(logn)复杂度计算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);
}

最小范围阈值为1,而不是10@PenchoIlchev它是否包含0是一种有争议的问题--(n^0)==n@rajneesh2k10好的,在4次运行中(从4的倍数开始),除了最低的位之外,所有的位都是相同的,所以它们在相互抵消或具有其原始值之间交替。的确,最低位周期每2次,但0^1==1(即,它们不会取消)。最低的两个之所以特别是因为(00^01^10^11)=00。换句话说,每循环4个值,就返回到0,因此可以取消所有这些循环,这就是为什么%4是重要的。@Pandrei
a
有2个,而不是0。该列是正在运行的xor,1 xor 2是3,因此该行中的当前值在我看来是正确的。我稍微编辑了一下你的问题。我们不介意解释一些代码的原因,但是我们不需要一个新的列表来解决这个问题。交给TopCoder吧。@Kev没问题!我写这篇文章是因为有些人喜欢用自己的方式,而不是解释已经写好的东西。任何新的想法都不是浪费……;)这让我想起了我去年在大学上的离散数学课程。有趣的日子。读了这篇文章后,我立刻想到了这一点。这篇文章的计算复杂度与普通的m^(m+1)^…^(n-1)^n计算。这是0(n)。