异或运算:相同为0,不同为1(无进位相加)
例子:6 ^ 7 = 110 ^ 111 = 001 = 1(十进制)
同或运算:相同为1,不同为0
🐕题目一:如何不用额外变量交换两个数
a = 666;
b = 888;
a = a^b
b = a^b ⇒ ( a^b )^b ⇒ a
a = a^b ⇒ ( a^b )^ a ⇒ b
此时 a、b 两个变量就交换了!
注意:使用位运算的前提是 俩变量不是同一块内存
🐱题目二:一个数组中有一种数出现了奇数次,其他数都出现了偶数次,如何找到这个奇数次的数
/*
已知一个整型数组中 存在 唯一 的一个奇数次的数 其余的数 都是偶数次 现在要找出这个奇数次的数
考点:异或运算
*/
public static void printOddTimesNum(int[] arrs) {
int num = 0;
for(int x:arrs) {
num ^= x;
}
System.out.println("奇数是:"+num);
}
😁题目三:怎么把一个int类型的数,提取出 最右侧的1
(如果有需要把一个数最右边的1提取出来就这样子写)
int rightOne = num1 & (~num1+1);
00100100 & ( 11011011 +1 )
00100100 & ( 11011100 )
与运算的运算规则是0&0=0; 0&1=0; 1&0=0; 1&1=1;即:两位同时为“1”,结果才为“1”,否则为0。
00100100 & ( 11011100 ) ⇒ 00000100 这样子最右侧的1就提取出来了~
😁题目四:一个数组中有两种数 出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数
/*
已知一个整型数组中 存在 两个 的奇数次的数 其余的数 都是偶数次 现在要找出这俩个奇数次的数
考点:异或运算
*/
public static void printTwoOddTimesNum(int[] arrs) {
int num1 = 0;
for(int x:arrs) {
num1 ^= x;
}
//异或完一遍后 结果肯定为 a ^ b 当前num1 != 0 且必然有一个位置上是1
//现在的想法就是把他们分离
int num2 = 0;
int rightOne = num1 & (~num1+1); // 提取最右边的1 (如果有需要把一个数最右边的1提取出来就这样子写)
for(int x:arrs) {
// 此时rightOne类似00100这种 再进行与运算 如果==0 则证明这个数的第三位上是0 (也是两个奇数中的一个)
if((x & rightOne) != 0) { // 此时这里只能 ==0 或 != 0 或 rightOne
num2 ^= x;
}
}
System.out.println("奇数分别为:"+num2 +" 、 "+(num1^num2));
}
🐖题目五:如何根据一个整数 求出 这个整数的二进制中 1 的个数
二进制整数 只有32位 ,最不济的方法就是遍历32次
/*
* 求一个整数 的二进制中有几个1
* 思路:每次取出最右侧的1
*/
public static int calcBinaryCounts(int num) {
int count = 0;
while(num != 0) {
int rightOne = num & (~num+1);
count ++;
//这里为啥不用 N -= rightOne呢,因为考虑到负数问题,而使用异或运算就没这个困惑
num ^= rightOne;
}
return count;
}