异或运算

1. 简介

异或运算XOR 是 exclusive OR 的缩写。英语的 exclusive 意思是"专有的,独有的",可以理解为 XOR 是更单纯的 OR 运算。

我们知道,OR 运算的运算子有两种情况,计算结果为true

  • 一个为 true,另一个为 false;

  • 两个都为 true。

上面两种情况,有时候需要明确区分,所以引入了 XOR

XOR 排除了第二种情况,只有第一种情况(一个运算子为true,另一个为false)才会返回 true,所以可以看成是更单纯的 OR 运算。也就是说, XOR 主要用来判断两个值是否不同

  • 相同为True
  • 不同为False

2. 性质

  • 一个值与自身的运算,总是为 false
  • 一个值与 0 的运算,总是等于其本身
  • 满足交换律和结合律

3. 应用

3.1. 简化计算

运用异或运算的性质进行计算简化

3.2. 交换值

利用异或运算的性质,实现无空间开销的交换数值:

private static void swap(int[] arr, int i, int j) {
arr[i] = arr[i]^arr[j];
arr[j] = arr[i]^arr[j];
arr[i] = arr[i]^arr[j];
}

3.3. 加密

  • 明文(text)与密钥(key)进行异或运算,可以得到密文(cipherText)

  • 密文与密钥再次进行异或运算,就可以还原成明文

3.4. 数据备份

  • 文件 x 和文件 y 进行异或运算,产生一个备份文件 z
  • 以后,无论是文件 x 或文件 y 损坏,只要不是两个原始文件同时损坏,就能根据另一个文件和备份文件,进行还原

4. 解决问题

4.1. 寻找仅出现一次的一个数

情景:某数列中只有一个数出现了一次,求该数

思路:按照异或运算的性质,亦或运算满足交换律和结合律,偶数次相同的数亦或的结果为0,0亦或任何数等于任何数,所以只需要将数列全部亦或运算即可

public int onlyOnceNum(int[] nums) {
int tmp = 0;
for(int i=0;i<nums.length;i++){
tmp = tmp^nums[i];
}
return tmp;
}

4.2. 寻找仅出现一次的两个数

情景:某数列中只有两个数出现了一次,求该两数

思路:按照前一题的思路,将所有数亦或运算得到这两数的亦或结果,由于两数一定不同,所以在二进制表示法上一定有的位数是1,按照两数亦或结果为1的位数是否为1划分数列中的数,得到分别包含两数的两个子数列,将其中一个数列全部亦或,得到该数列中的这个数,与之前两数亦或的结果再亦或一次得到另一个数

public int[] onlyOnceTwoNums(int[] nums) {
int tmp = 0;
for(int i=0;i<nums.length;i++){
tmp = tmp^nums[i];
}
//获得二进制最右边的1
int rightOne = tmp & (~tmp + 1);
int tmp2 = 0;
for(int i=0;i<nums.length;i++){
if ((nums[i] & rightOne) == 0)
tmp2 = tmp2^nums[i];
}
return new int[]{tmp^tmp2, tmp2};
}

4.3. 寻找缺失的数

情景:在范围0~n-1内的n个数字中有且只有一个数字不在该数组中,求该数

思路:将所有数亦或运算再与0~n-1内的所有数亦或运算即可得到该数

public int missingNumber(int[] nums) {
int tmp = 0;
for(int i=0;i<nums.length;i++){
tmp = tmp^i^nums[i];
}
return tmp^(nums.length);
}

5. 参考资料

[1]异或运算 XOR 教程 - 阮一峰的网络日志 (ruanyifeng.com)

[2]剑指 Offer 53 - II. 0~n-1中缺失的数字 - 力扣(LeetCode) (leetcode-cn.com)

posted @   当时明月在曾照彩云归  阅读(263)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示