异或的妙用(C语言)


按位异或 是在二进制位上的运算:
一句话概括,就是 同为0,异为1。 0 ^ 0 = 0 1 ^ 1 = 0 0 ^ 1 = 1 1 ^ 0 = 1

异或有何用?有妙用。有何妙用?有以下妙用。

首先来回顾一下异或的运算性质:

0 ^ n = n n ^ n = 0 a ^ b = b ^ a (a ^ b) ^ c = a ^ (b ^ c) 其中 a, b, c, n 均为整数。

将上面转换为文字就是:

0 与任何整数异或,结果都是原来的整数 任何整数跟自身异或的结果都是 0 异或运算满足交换律 异或运算满足结合律

题目一

题目描述: 数组 nums 包含从0到n的所有整数,但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗?
示例 1: 输入:[3,0,1] 输出:2
示例 2: 输入:[9,6,4,2,3,5,7,0,1] 输出:8
int missingNumber(int* nums, int numsSize){
          
   
    int x = 0;
    for(int i = 0; i <= numsSize; i++)
    {
          
   
        x ^= i;
    }

    for(int i = 0; i < numsSize; i++)
    {
          
   
        x ^= nums[i];
    }

    return x;
}
代码说明: 第一个循环结束后,x = 0 ^ 1 ^ 2 ^ 3 ^ … ^ n . 第二个循环结束后,x 就是缺的那个数 比如示例 1: 第一个循环结束后,x = 0 ^ 1 ^ 2 ^ 3 . 第二个循环结束后,x = 0 ^ 1 ^ 2 ^ 3 ^ 3 ^ 0 ^ 1 = 2 .

题目二

题目描述: 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1: 输入:nums = [4,1,4,6] 输出:[1,6] 或 [6,1]
示例 2: 输入:nums = [1,2,10,4,1,4,3,3] 输出:[2,10] 或 [10,2]
int* singleNumbers(int* nums, int numsSize, int* returnSize){
          
   
    int ret = 0;
    for(int i = 0; i < numsSize; i++)
    {
          
   
        ret ^= nums[i]; 
    }
	 //上面的循环结束后,ret 的值是两个只出现一次的数字异或的结果
	 // ret 的二进制位上为 1 的位,就是两个数在这个位上是不同的
	 //比如 ret = 0101 ^ 1001 = 1100 ,也就是说两个数不同的位是从右向左数的第3、4位
	 
    int m = 1;    //用 m 来找出 ret 的二进制位中从右向左的第一个为 1 的位
    //不会是死循环,因为 ret 是两个不同的数字异或的结果,其二进制位中至少有一位是1. 
    while((ret & m) == 0)  
    {
          
    
        m <<= 1;
    }
    //此时的 m 只有一位是1,那一位所在的位置正是ret从右向左数的第一个为1的位
    //依靠 m 的这个为1的位分别把数组元素分为两组:一组是在这个位上为0的,另一组是在这个位上为1的.
    //出现两次的数字必然分到同一组
    //也就是说下面的几步能够分离出两个只出现一次的数
    int a = 0, b = 0;
    for(int i = 0; i < numsSize; i++)
    {
          
   
        if((nums[i] & m) == 0)
            a ^= nums[i];
        else
            b ^= nums[i];
    }
    
    int* retArr = (int*)malloc(sizeof(int)*2);
    retArr[0] = a;
    retArr[1] = b;
    *returnSize = 2;
    return retArr;
}
注:按位运算符( & 、^ 、 | )的优先级比 == 和 != 的优先级要低,因此想要先按位运算再判断等还是不等,要给按位运算套上一层括号才行。

如果不知道异或运算的性质,是很难想到题目的解决是与异或有关的,或者说根本想不到。就算知道异或运算的性质,也很难一下子想出来。只有做题做多了,才有如此思路。

更多文章

经验分享 程序员 微信小程序 职场和发展