位运算的异或 “^” 运算符
0. 异或原理
- 0 ^ N = N;
- N ^ N = 0;
- 满足交换律 和 结合律。
1. 交换两个数的值
a = a ^ b;
b = a ^ b;
a = a ^ b;
- 思路演示:
为了方便演示不同的 \(a, b\) 分别定义新变量。
- a_1 = a ^ b;
- b_1 = a_1 ^ b = a ^ b ^ b = a;
- a_2 = a_1 ^ b_1 = a ^ b ^ a = b;
2. 求解数组内奇数次的唯一数
- 假设数组 arr 内有唯一的一个数出现了奇数次,其他数出现偶数次,求解这个唯一数:
int eor = 0;
for(int i; i < arr.length(); i++)
{
eor ^= arr[i];
}
System.out.println(eor);
3. 求解某数的二进制位的最右是 1 的位置
int i = eor & (~eor + 1);
3.1 求解数组内奇数次的唯一的两个数
- 假设数组 arr 内有唯一的两个数出现了奇数次,其他数出现偶数次,求解这两个唯一数。
- 思路与求一个一样,但是求出的是两个唯一数的异或,需要在进行拆分:
- 而两个数不一样代表着异或运算不为0,则这两个数至少有一位是不一样的,即运算结果至少保存一个位置的 1。
- 此时可以使用求解最右的 1 位置,利用这个结果与数组内元素进行 与运算,将结果为 0(或1)的元素保留下来,与 0 进行异或运算,最后剩下的为其中的一个数;
- 在利用这个数和两数的异或进行异或运算,的到另一个数。
int eor = 0;
for(int i; i < arr.length(); i++)
{
eor ^= arr[i]; // 两数的异或
}
int i = eor & (~eor + 1); // 求两数不同的最右的 1 位置
int ~eor = 0;
for(int i; i < arr.length(); i++)
{
if(i & arr[i] == 0){
~eor ^= arr[i]; // 两数的其中一个
}
}
System.out.println(~eor + " " + (eor ^ ~eor)); // 输出两个数