问题描述:
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
按位异或相关知识:
按位异或性质:将数转化成2进制,2个数相同异或为0,2数不同异或为1: 0^0=0,1^1=0;0^1=1。(与1异或,得该位元素的反,与0异或,得该位元素)
满足结合律和交换律。
按位异或典型用途:
1、交换两个整数的值而不必用第三个参数
a = 9, b = 11;
a=a^b; 1001^1011=0010
b=b^a; 1011^0010=1001
a=a^b; 0010^1001=1011
得到:a = 11,b = 9;
2、求一个位串信息的某几位信息的反。如欲求整型变量J的最右4位信息的反,用逻辑异或运算015^J,就能求得J最右4位的信息的反,即原来为1的位,结果是0,原来为0的位,结果是1。
本题思路:
如果一个数组,只有1个元素出现1次,其他元素都出现2次,将所有元素异或,结果即为出现1次的元素(相同元素异或为0,0与元素异或为本身)。
将题目中的数组分成2个分别只含有1个出现1次的元素,其他都是出现2个的元素,即可使用上面的性质求解。
数组分割:
将所有元素异或,即为2个不同的元素的异或,找到第一个为1的位(不同),然后按照该位为1和为0的分成2个数组,即为只含1个不同元素数组。每个数组中所有元素异或,记得到2个要找的不同的数
代码:
#include <iostream>
using namespace std;
void FindTwoDiffNum(int *arr, int len)
{
int tmp=0, i=0;
for (i=0;i<len;i++)
tmp=tmp^arr[i];//两个不同元素的异或
int count=0;//移动位数
while ((tmp & 0x01)==0)//取最后1位
{
tmp>>1;//右移1位
count++;
}
//不需要数组分组,只要存储异或结果即可
int leftResult=0 ,rightResult=0;
for (i=0;i<len;i++)
{
if (((arr[i]>>count) & 0x01)==0)//最后一位相同
leftResult=leftResult^arr[i];
else
rightResult=rightResult^arr[i];
}
cout<<leftResult<<' '<<rightResult<<endl;
}
int main()
{
int arr[]={1,2,3,4,5,3,2,1};
FindTwoDiffNum(arr,8);
int arr2[]={1,2,3,8,7,3,2,1};
FindTwoDiffNum(arr2,8);
system("pause");
return 0;
}