题目:
在一个数组中,只有两个不相同的数出现奇数次,其余都出现过偶数次,求找出那两个数字,要求时间复杂度为O(n),空间复杂度为O(1).
性质:
1)0^N=N N^N=0
2)满足交换律。
思路:
1)假设那两个出现奇数次的分别为a、b,先将所有数异或到ero上,结果ero=a^b≠0,
2)然后找到ero二进制位为1的那一位,然后将数祖中数按照这一位分为两组A、B,
3)然后将A、B中数分别全部异或在一起,即为所求答案a,b。
问题解释:
1)为什么要找那个1
比如a=3,b=5,ero=a^b
3 011
5 101
ero 110
比如找最后一个1,即ero中的倒数第二位,往上看3和5对应的那一位二进制数字、分别是1和 0,所以就有了区分,就可以按照这一位分别分出两组,一组包含3在内的所有该位为1的数字,一组包含5在内的所有该位为0的数字。
2)怎样找出最后那一个1
比如
ero: 10101100
~ero: 01010011
~ero+1: 01010110
ero&(~ero+1): 00000100
那么最后那一位1就找到了。
3)怎么按照那一位分成两组呢
arr[i]&(ero&(~ero+1))==0说明那一位不是1;arr[i]&(ero&(~ero+1))!=0说明那一位是1。
代码实现:
void find(int arr[],int sz){
int ero=0;
for(int i=0;i<sz;i++)
ero^=arr[i];
int rightone=ero&(~ero+1);//提取最右的1
int onlyone=0;
for(int i=0;i<sz;i++){
if(arr[i]&rightone==0)//分类
onlyone^=arr[i];
}
cout<<onlyone<<" "<<ero^onlyone<<endl;//a^b^a=b
}
EOF!!!