【题解】《算法零基础100讲》(第46讲) 位运算 (异或) 入门

概念定义

1.1 异或运算符

  异或运算符也是对两个数进行按位计算,例如:x ^ y
  其计算方式如下表所示:

x y x ^ y
1 1 0
1 0 1
0 1 1
0 0 0

总结一下就是按照相同为0,相异为1的方式计算。

同时我们还能得出一些结论:

  1. 两个相同的数结果一定为0
  2. 任何数与0按位异或的结果一定为其本身
  3. 异或运算满足交换律和结合率

1.2 按位异或的运用

1.2.1 标记为取反

给定一个数,将其从最低位开始第四位数进行取反,即0变1,1变0。

  题目要求我们对第四位取反,那我们只需要对0b1000进行按位异或

代码如下:

#include <stdio.h>
int main() {
    
    
    int x;
    scanf("%d", &x);
    x ^= 0b1000;
    printf("%d\n", x); 
    return 0;
}

1.2.2 变量交换

  通常我们进行变量交换都是会设置一个中间变量,当异或运算有这样一个结论,我们假设有两个变量a和b,a ^ b ^ b的结果是a,b ^ a ^ a的结果是a。所以我们可以通过异或运算进行交换。

代码演示:

#include <stdio.h>
int main() {
    
    
    int a, b;
	while (scanf("%d %d", &a, &b) != EOF) {
    
    
	    a = a ^ b;   
	    b = a ^ b;   //这里就相当于a ^ b ^ b
	    a = a ^ b;   //这里相当于 b ^ a ^ a
	    printf("%d %d\n", a, b);
	}
	return 0;
}

1.2.3 出现奇数的次数

给定一组数据,数组中只有一个数据只出现过奇数次,其他都能找到成对的,请找出哪个奇数次的数据。

分析:

根据上面的定理我们知道,相同的数异或运算后为0,同时异或运算符合交换率和结合律,我们假设有这也一组数{1,2,3,1,2,3,4}。我们将其全部进行异或运算,得到这样一个式子:

1 ^ 2 ^ 3 ^ 1 ^ 2 ^ 3 ^ 4
通过交换率,我们由得到上式等于:
1 ^ 1 ^ 2 ^ 2 ^ 3 ^ 3 ^ 4
最后的结果就是:
0 ^ 0 ^ 0 ^ 4 = 4

代码如下:

#include <stdio.h>
int main() {
    
    
    int n, x, i, ans;
    scanf("%d", &n);
    ans = 0;//任何数异或0为其本身
    for(i = 0; i < n; ++i) {
    
    
        scanf("%d", &x);
        ans = (ans ^ x);
    } 
    printf("%d\n", ans);
    return 0;
}

二. 推荐专栏

《算法零基础100讲》(第46讲) 位运算 (异或) 入门

三. 相关练习

3.1 只出现一次的数字

136. 只出现一次的数字

这道题我们可以直接将数组内所有数字进行按位异或计算,最后的值就是只出现一次的值。

代码如下:

int singleNumber(int* nums, int numsSize){
    
    
    int ans = 0;//任何数异或0为其本身
    for(int i = 0; i < numsSize; i++){
    
    
        ans ^= nums[i];
    }
    return ans;
}

在这里插入图片描述

3.2 颠倒二进制位

190. 颠倒二进制位

将 nn 视作一个长为 3232 的二进制串,从低位往高位枚举 nn 的每一位,将其倒序添加到翻转结果rev 中。
代码实现中,每枚举一位就将 nn 右移一位,这样当前 nn 的最低位就是我们要枚举的比特位。当 nn 为 00 时即可结束循环。

代码如下:

uint32_t reverseBits(uint32_t n) {
    
    
    uint32_t rev = 0;
    for(int i = 0; i < 32 && n > 0; i++){
    
    
        rev |= (n & 1) << (31 - i);//将n的末尾位的数赋给rev的(31-i)位
        n >>= 1;//n右移1位
    }
    return rev;
}

在这里插入图片描述

3.3 汉明距离

461. 汉明距离

我们可以通过按位与&运算,对尾部的数字进行比较,比较完后,再将两个数同时右移一位,在判断下一位是否相等,以此类推

代码如下:

int hammingDistance(int x, int y){
    
    
    int cnt = 0;
    for(int i = 0; i < 32 && (x > 0 || y > 0); i++){
    
    
        int xw = x & 1;
        x >>= 1;
        int yw = y & 1;
        y >>= 1;
        //printf("%d %d,", xw, yw);
        if(xw != yw){
    
    
            cnt++;
        }
    }
    return cnt;
}

在这里插入图片描述

3.4 数组异或操作

1486. 数组异或操作

这道题我们直接根据公式start + 2 * i 求出每个值,同时进行异或计算。

代码如下:

int xorOperation(int n, int start){
    
    
    int ans = 0;
    for(int i = 0; i < n; i++){
    
    
        ans ^= (start + 2 * i);
    }
    return ans;
}

在这里插入图片描述

Guess you like

Origin blog.csdn.net/qq_53060585/article/details/121744094