前言
异或运算满足交换律以及结合律可以推断出来三个性质
①0^N=N
②N^N=0
交换律:
ab=ba
结合律:
(ab)c=a(bc)
③交换律结合律 = 同一个数
相同为0,不同为1
a^b=c
二进制数a: 0 1 1 1 0
二进制数b: 0 0 1 0 1
------------
等于c: 0 1 0 1 1
那么交换律和结合律就是
题目一、如何不用额外的变量交换两个数
int main(int argc,int *argv[]) {
int a = 17;
int b = 13;
//假设现在a是 甲 b是 乙
a = a ^ b; //a= 甲^乙
b = a ^ b; //b= 甲^乙^乙
a = a ^ b; //a= 甲^乙^甲
system("pause");
return 0;
}
题目二、一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
int oddTimesNum(std::vector<int> &arr) {
int eor = 0;
for (int i = 0; i < arr.size(); ++i) {
eor ^= arr[i];
}
return eor;
}
题目三、怎么把一个int类型的数,提取出最右侧的1来
int main(int argc,int *argv[]) {
int a = 110;
int b = a & (~a + 1); //(~a+1)是自己的相反数
system("pause");
return 0;
}
题目四、一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数
题目二是打印一种,此题打印两种
void oddTimesNum(std::vector<int> &arr) {
int eor = 0;
for (int i = 0; i < arr.size(); ++i)
eor ^= arr[i];
//eor≠0
//例:eor= 00110010110111000
//那么rightOne = 00000000000001000
int rightOne = eor & (~eor + 1); //提取出最右的1
int onlyOne = 0;
for (int i = 0; i < arr.size(); ++i) {
if ((arr[i] & rightOne) != 0)
onlyOne ^= arr[i];
}
std::cout << onlyOne << "\t" << (eor ^ onlyOne) << std::endl;
}
题目五、一个数组中有一种数出现K次,其他数都出现了M次,M>1,K<M找到出现了K次的数,要求额外空间复杂度O(1),时间复杂度O(N)
int onlyKtimes(std::vector<int>& arr, int k, int m) {
std::vector<int> ret(32);
//ret[0] 0位置的1出现几个
//ret[i] 0位置的1出现几个
for (int num : arr) {
for (int i = 0; i <= 31; ++i) {
ret[i] += (num >> i) & 1;
//相当于↓↓↓这个判断
/*if (((num >> i) & 1) != 0){
ret[i]++;
}*/
}
}
int ans = 0;
for (int i = 0; i < 32; i++) {
if (ret[i] % m == 0) {
continue;
}
if (ret[i] % m == k) { //在第i位上有1
ans |= (1 << i);
}else {
return -1;
}
}
if (ans == 0) {
int count = 0;
for (int num : arr) {
if (num == 0) {
count++;
}
}
if (count != k) {
return -1;
}
}
return ans;
}
= 0;
for (int num : arr) {
if (num == 0) {
count++;
}
}
if (count != k) {
return -1;
}
}
return ans;
}