异或运算
0 ^ 0 = 0,1 ^ 1 = 0,0 ^ 1 = 1; 相同为0,不同为1
异或运算满足交换律和结合律
c =a ^ b =b ^ a
c =( a ^ b )^ c = a ^ ( b ^ c )
所以
a^b ;
a ^ b ^b=a;
a ^ b ^a=b;
如果是一个数组里一个数出现奇数次,那么对这个数组从头到尾异或,最终的等于的是出现奇数次的数, 因为偶数次的数在异或之后都等于0了 。
如果是一个数组,两种数出现了奇数次,其他数出现了偶数次;
假设奇数次的数为 a,b;定义一个变量,对数组从头到尾异或,最终的结果是eor=a^b;
int eor = 0;
for (int i = 0; i < l; i++)
{
eor ^= a[i]; //异或之后eor=a^b
}
那怎么分开ab;
因为a和b是不同的两个数,所以eor一定不等于0;所以异或之后eor至少有一位为1;假设eor的第八位是1,那么a和b的第八位一定是不相同的
例如,eor=2 ^ 3 ;
00000010
00000011
-------------
00000001 = eor
eor=2^4;
00000010
00000100
-------------
00000110 = eor
随便取到一位数为1的,可以通过这个位置区分数组中的元素,分别是在这个位上为1的和0的两种类型。
例如,分成第八位是1和第八位是0的数,a,b的第八位一定不同,所以两个数被分到不同阵营里。
此时再定义一个变量,对其中一个阵营里的数再异或,偶数次数的依旧为会异或为0,而异或的结果则为a或b中的一个,比如这个数是a,将它与eor异或之后就能得到b,(eor=a^b);
关于取到最右边是1的那一位:
~eor 取反
~eor + 1 取反加一
eor & (~eor + 1)
void TimesNum(int a[], int l)
{
int eor = 0;
for (int i = 0; i < l; i++)
{
eor ^= a[i];
}
int right = eor & (~eor + 1);//取到最右边一位1
int onlyOne = 0;
for (int i = 0; i < l; i++)
{
if ((right & a[i])==0)//&运算:同为1才等于1,判断等于0是将对这个位上是0的数异或
{ //也可以==1,是将对这个位上是1的数异或
onlyOne ^= a[i];
}
}
int nu = eor ^ onlyOne;
cout << onlyOne << " " << nu << endl;
}
:左程云老师的课