异或运算

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 @ 2022-03-14 13:38  当时明月在曾照彩云归  阅读(255)  评论(0编辑  收藏  举报