找出2n+1个数中不成对的那个

在网上看到一篇相关的文章,感叹算法的巧妙。

用O(n)复杂度搞定。

异或操作(^)——(对于操作)相同为0,相异为1.比如:1^0 = 1, 1 ^1=0

这样:

  • 两个相同的数异或就为0
  • 任何数和0异或为自己(转化到位。1^0 = 1, 0 ^0=0

对于2,1,3,2,1, (2^2)^(1^1)^3=3.如此就能将不成对的3找出来。

异或具有交换律,所以可以按顺序计算,2^1^3^2^1=3。

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int a[7] = {1, 2, 1, 2, 3, 5, 5};

int main(){
    int i, ans = 0;

    for(i=0; i<7; i++){
        ans ^= a[i];
    }

    printf("%d\n", ans);
    return 0;
}

问题升级版:

(1)给出n个数,其中有且仅有一个出现了奇数次,其余的都出现了偶数次。用线性时间常数空间找出这个出现奇数次的数

(2)给定n个数,其中有且仅有两个出现了奇数次,其余的都出现了偶数次。用线性时间常数空间找出这两个出现奇数次的数

对于问题1,就不解释了。

对于问题2,

1.对所有的数异或一遍,得到的数肯定不为0,

2.在二进制中从右向左找第一个值为1的位置,也就是说这两个出现奇数次的数的二进制在此位置的值肯定不同,按照在这个位置的不同值(即0或1)将所有数分成两组,分别异或运算,所得的结果就是这两个出现奇数次的数。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int a[6] = {4, 3, 1, 56, 3, 1};

int main(){
    int i, ans1, ans2, k, pos;
    k=0;
    for(i=0; i<6; i++) k ^= a[i];

    for(pos=1; (k&pos) == 0; pos<<=1);

    ans1 = ans2 = 0;

    for(i=0; i<6; i++){
        if((a[i]&pos) == 0) ans2 ^= a[i];
        else ans1 ^= a[i];
    }

    printf("%d %d\n", ans1, ans2);

    return 0;
}

原文地址1:http://www.cnblogs.com/kaituorensheng/archive/2013/04/03/2998829.html

原文地址2:http://www.cnblogs.com/kaituorensheng/archive/2013/04/04/3000033.html

原文地址:https://www.cnblogs.com/tanhehe/p/3000658.html