先看一道题:
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; }
但是如果要是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