2021 后端开发笔记 20 异或运算算法题

首先让我们来看看什么是异或运算

异或运算:相同为0不同为1
同或运算:相同为1不同为0

同时我们还需要知道异或运算的性质
1. 0 ^ N == N
2. N ^ N == 0
这两个性质非常重要哦!待会会频繁用到

接下来我们从题目开始:

题目1:

如何不用额外变量交换两个数?

大家都知道在Python中是不需要的,那么如果在Java中我们就需要使用额外的一个变量先去记录一个值,然后再去交换。
像是这样: int a = 10;, int b = 5;,我们就需要先用一个临时变量记录其中一个值, 例如:
int temp = a; 然后再去交换 a = b, b = temp 这样我们的交换就完成了。

但是这需要用到额外变量,那么我们如何不适用额外变量就能替换两个值呢?我们就需要用到异或了 。
根据异或的性质,N 异或 N == 0,所以我们可以 用 a 异或 a 然后再异或 b,a是不是就变成了b呢?

让我们来看看代码实现,其实就是这么简单的几行代码,我们用a来替代了额外变量,第二行就相当于a ^ b ^ b我们就得到了a,然后让b接收了这个 变量我们就进行了交换。然后再用新的b也就是a,异或 a ^ b,也就是 a ^ b ^ a,得到了b。这样我们就完成了交换

a = a^b;
b = a^b;
a = a^b;
题目2:

一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数字?

我们同样也可以用到之前的异或的性质,两个相同的数字如果异或一定为0,所以我们只要将所有的数字异或,我们就能得到出现了奇数次的数字。

让我们来看代码:
申请一个变量接收异或的结果,然后循环数组中所有数字,和额外变量异或,最后返回结果就行了

public class QuestionTwo {
    public static int oddTimeNum(int[] arr){
        int eor = 0;
        for(int num: arr){
            eor ^= num;

        }
        return eor;
    }
}
题目3:

如何把一个int类型的数,提取出二进制形式最右侧的1来?
提取最右侧的数字我们只要 !!!把这个数字和它的负数做相位与就好了

我们先来说说在二进制里面一个负数是怎么表示的,首先将这个数上的所有位取反然后+1
例如数字3:二进制表示是011,负数就是取反100,然后+1,就是101
然后我们再将 3 和 -3做相位与 011 & 101,答案就是001这样我们就提取出来最右侧的1了。

前面都是我缩短了之后实际上在计算机里面的状态是

(这个表示3)

(这个是反码)

(+1变成 - 3)

(和原来的3与完之后)

代码只有两行

int a = 3;
int rightOne = a & (-a); 
题目4:

题目2的升级版,如果有两个数出现了奇数次,其他数字出现了偶数次,怎么找到这两个奇数,并且打印出来?

听起来很难?其实思路也是利用异或的性质。

  1. 我们先将所有数字异或,这样我们就能得到a 异或 b(因为出一个数字偶数次异或都为0)。

  2. 然后我们在提取出a异或b的二进制上的任何一个1,为什么要这样做?因为只有a或者b上有1那一位才有1,所以我们拿着这个1和原数组中这个位置上有1的进行异或,我们是不是就能把其中一个数字提取出来?

  3. 然后我们再将这个数字和a异或b去异或,这样我们就能拿出另个一数字。

为了方便我们取a异或b最右边的1,上面那题已经说过了,我们将a异或b用变量eor来表示,就是eor逻辑与上-c

接下来我们来看代码:

public static void OddTimeNum(int[] arr){
        // 用来存储数组中所有数字都被异或了的结果
        int eor = 0;
        for(int num : arr){
            eor ^= num;
        }
        // 提取最右侧的1
        int rightOne = eor & (-eor);
        
        // 存储其中一个数字
        int oneOfTwo = 0;
        for(int num : arr){
            // 如果这个数字上那个位置有1,就不是我们想找的
            if((num & rightOne) != 0){
                oneOfTwo ^= num;
            }
        }
        System.out.println(oneOfTwo);
        System.out.println(eor ^ oneOfTwo);
    }

Reference: https://italk.mashibing.com/course/detail/cour_00004003

你可能感兴趣的:(2021 后端开发笔记 20 异或运算算法题)