在网上看到一篇相关的文章,感叹算法的巧妙。
用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