先看一道题:
Single Number
Given an array of integers, every element appears twice except for one. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?
void main(){
int t=0;
for(int i=0;i<n;i++){
t^=A[i];
}
printf("%d\n",t);
}
如果将题目改一下,若剩下的不是一个元素,而是剩下两个不同的元素,求其和呢?
如果还像上面那样求,最后出来的结果是这两个不同元素异或的值,不是最终结果,利用异或的结果也是求不出两个值的和的,所以要换种思路。
有一种思路是,定义一个比较大的数组,大于n位数组中每一个正整数,数组中存放该数值是否被访问过,被访问第二次就把该值变为0;
定义一个存放结果的变量result,初始值定义为0。
遍历数组,如果该元素被访问一次,则将该值加到result上,否则(包括访问0次或2次)从result中减掉该值。
具体实现如下:
int main() {
freopen("C:\\in.txt","r",stdin);
int n,g,result,i;
bool vis[10005];
while(~scanf("%d",&n)){
result=0;
for(i=0;i<=10000;i++)vis[i]=0;
for(i=0;i<n;i++){
scanf("%d",&g);
if(!vis[g])result+=g;
else result-=g;
vis[g]^=1;
}
printf("%d\n",result);
}
return 0;
}
其中用到了vis[g]^=1,也就是将该值取反,异或速度会比比较然后再赋值快。
但是如果要是n值非常大或者是数组中可以有负值,这个方法就不行了
另一种思路还是二进制的思想,我们将所有的数进行异或,结果一定是那两个不同的数的异或值,因为两个数不同,所以异或值不为0,我们根据异或值中某一位1的位置,将数组分为两个数组,每个数组中都符合只有唯一的一个不同的数
#include <iostream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int main(){
int a[10]={1,2,3,1,2,3,4,4,5,6};
int arr1[5],arr2[5];
int t=0;
//先做异或
for(int i=0;i<10;i++)
t^=a[i];
//找到t二进制中最后的1的位置
int idx=1;
while(!t&idx)idx<<=1;
//根据idx位置是0或1将数组a分成arr1和arr2两个数组
int j1=0,j2=0;
for(int i=0;i<10;i++)
if(a[i]&idx)arr1[j1++]=a[i];
else arr2[j2++]=a[i];
int t1=0,t2=0;
for(int i=0;i<j1;i++)t1^=arr1[i];
for(int i=0;i<j2;i++)t2^=arr2[i];
cout<<t1<<" "<<t2<<endl;
return 0;
}
然后还有一题,大意是数组n中除了一个元素只出现一次外,其他元素全部出现3次,求这个特殊的元素,这道题通过位运算可以在线性时间内求出结果,
具体参见我的另一篇文章:http://blog.csdn.net/starcuan/article/details/18219623