LeetCode刷题笔记 位运算巧解算法题 位运算基础

​ 位运算是算法题里比较特殊的一种类型,它们利用二进制位运算的特性进行一些奇妙的优化和计算。常用的位运算符号包括:“∧” 按位异或、“&” 按位与、“|” 按位或、“∼” 取反、“<<” 算术左移和 “>>” 算术右移。以下是一些常见的位运算特性:

异或
x ^ 0000 = x x & 0000 = 0 x | 0000 = x
x ^ 1111 = ~x x & 1111 = x x | 1111 = 1111
x ^ x = 0 x & x = x x | x = x

​ 除此之外, n & (n - 1) 可以去除 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,减去 1 得到 11110011,这两个数按位得到 11110000。

​ n & (-n) 可以仅保留 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,取负得到 00001100,这两个数按位与得到 00000100。

​ 回顾一下移位操作,移位操作是一种基本操作,是一种直接对二进制数据的位运算操作,移位运算又包含了逻辑移位(logical shift)和算术移位(arithmetic shift)两种。

  • 逻辑移位:移出去的位丢弃,空缺位(vacant bit)用 0 填充。
  • 算术移位:移出去的位丢弃,空缺位(vacant bit)用“符号位”来填充,所以一般用在右移运算中。

​ 无符号数,不管是左移还是右移都是逻辑移位;有符号数,做左移运算是逻辑移位,而做右移运算是算术移位。

461 汉明距离

给定两个十进制数字,求它们二进制表示的汉明距离(Hamming distance,即不同位的个数)。

输入是两个十进制整数,输出是一个十进制整数,表示两个输入数字的汉明距离。

输入:x = 1, y = 4
输出:2
解释:1 (0 0 0 1);4 (0 1 0 0)

解析:

​ 求二进制数不同位的个数,直接使用将俩个数进行按位异或操作,不同位的结果就是 1,所以最终统计异或结果中的 1 的个数即可。

​ 计算二进制数 1 的个数的方法:不断将二进制数算数右移,将其与 1 进行与运算,如果末位是 1 则加入计数。

class Solution {
    
    
public:
    int hammingDistance(int x, int y) {
    
    
        // 异或运算
        int diff = x^y;
        int ans = 0;
        while(diff){
    
    
            // 与运算 判断末位是否为 1
            ans += diff & 1;
            // 算术右移动 将已经被统计的 1 移出
            diff = diff>>1;
        }
        return ans;
    }
};

190 颠倒二进制位

给定一个十进制整数,输出它在二进制下的翻转结果。

输入和输出都是十进制整数。

输入:n = 00000010100101000001111010011100
输出:964176192 (00111001011110000010100101000000)
解释:将 n 的二进制串倒转

解析:

​ 使用算术左移和右移,可以很轻易地实现二进制的翻转。保存结果的二进制串每次向左移动一位腾出末位,然后将 n 与 1 取出 n 的末位并放入结果腾出的末位,放入之后 n 向右移动一位将已放入的位移出。

​ 一个简单的示例:

1 2 3 4 5
ans (算术左移) 0000 0000 0001 0010 0101
n (算术右移) 1010 0101 0010 0001 0000
class Solution {
    
    
public:
    uint32_t reverseBits(uint32_t n) {
    
    
        // 无符号32位整型
        uint32_t ans = 0;
        for(int i=0;i<32;++i){
    
    
            // 每次先将结果左移一位腾出位置
            ans <<= 1;
            // 将 n 当前的最后一位放到上一步ans腾出的位置(末位)
            ans += n&1;
            // 将已经放入结果的位移出
            n >>= 1;
        }
        return ans;
    }
};

693 交替位二进制数

给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现

输入一个整数,输出一个布尔类型表示二进制表示是否总是 0、1 交替出现

输入:n = 10
输出:true
解释:10 的二进制表示是:1010

解析:

​ 一种简单的思路是不断使用算术右移将n的二进制表示末位移出,使用按位与运算获取末位是0还是1,并且比较第 i 个和第 i-1 个末位是否相同,如果相同则直接返回false,检查完成则返回true。

class Solution {
    
    
public:
    bool hasAlternatingBits(int n) {
    
    
        // 记录第一个末位
        int pre = n & 1;
        n>>=1;
        while(n){
    
    
            // 比较第 i 个和第 i-1 个末位
            int now = n & 1;
            if(now == pre){
    
    
                return false;
            }else{
    
    
                // 更新前一个状态
                pre = now;
            }
            n >>= 1;
        }
        return true;
    }
};

参考资料

LeetCode 101:和你一起轻松刷题(C++) 第 10 章 神奇的位运算

Guess you like

Origin blog.csdn.net/qq_41773806/article/details/120784291