【每日算法】专题五_位运算

1. 常见的运算总结

1.1. 基础位运算

按位与(&):有 0 就是 0

按位或(|):有 1 就是 1

按位异或(^):相同为 0,相异为 1 / 无进位相加

按位取反(~):逐位翻转,0→1,1→0

左移(<<):整体左移,右侧补 0

右移(>>):整体右移,左侧补符号位(正补 0,负补 1)

1.2 给一个数n,确定它的二进制表示中的第 x 位是 0 还是 1

bash 复制代码
(n >> x) & 1

1.3 将一个数 n 的二进制表示的第 x 位修改成1

bash 复制代码
n |= (1 << x)

1.4 将一个数 n 的二进制表示的第 x 位修改成 0

bash 复制代码
n &= (~(1 << x))

1.5 位图的思想

位图的核心思想是用二进制位(bit)表示数据状态,通过每一位的 0/1 标记 "不存在 / 存在",将离散数据映射到连续位空间,利用位运算实现高效存储与操作。

1.6 提取一个数 n 二进制中最右侧的1

bash 复制代码
n & -n

1.7 干掉一个数 n 二进制表示中最右侧的 1

bash 复制代码
n & (n - 1)

1.8 异或(^)运算的运算律

bash 复制代码
a ^ 0 = a

a ^ a = 0

a ^ b ^ c = a ^ (b ^ c) 

2.例题

2.1 面试题 01.01. 判定字符是否唯一

面试题 01.01. 判定字符是否唯一 - 力扣(LeetCode)

cpp 复制代码
    bool isUnique(string astr) {
        // 运用位图的算法思想可以很轻松的解决这道题
        // 在整数的32bit位中一个bit位对应一个字符
        // 通过二进制位的 0/1 表示字符 "没出现过 / 出现过"

        if(astr.size() > 26) return false;// 当字符串长度大于26必然会出现重复的字符,直接返回false

        int bitMap = 0;
        for(auto ch : astr)
        {
            int i = ch - 'a';
            if((bitMap >> i) & 1) return false;// 字符对应的字节位置为1时说明字符重复出现
            bitMap |= (1 << i);// 给字符对应的字节位置标1
        }

        return true;
    }

2.2 丢失的数字

268. 丢失的数字 - 力扣(LeetCode)

cpp 复制代码
    int missingNumber(vector<int>& nums) {
        int bitMap = 0;
        for(int i = 0; i <= nums.size(); ++i)
            bitMap ^= i;

        for(auto i : nums)
            bitMap ^= i;

        return bitMap;
    }

2.3 两整数之和

371. 两整数之和 - 力扣(LeetCode)

cpp 复制代码
    int getSum(int a, int b) {
        // (a ^ b)可以进行无进位相加,(a & b) << 1可以把进位提出来。
        // 用进位与上一个无进位相加的结果进行无进位相加,继续把相加的进位提出来。
        // 以此循环知道进位为零为止。
        int ret = a ^ b;
        int Carry = (a & b) << 1;
        while (Carry)
        {
            int tmp = ret;
            ret = ret ^ Carry;
            Carry = (tmp & Carry) << 1;
        }
        return ret;
    }

2.4 只出现一次的数字 II

137. 只出现一次的数字 II - 力扣(LeetCode)

cpp 复制代码
    int singleNumber(vector<int>& nums) {

        // 将所有数的相同二进制位对应的1或0相加
        // 假设某个元素出现三次,且其对应的二进制位为1
        // 我们只需要将相加的结果模3就可以把出现三次的元素去掉,
        // 那么剩下就是仅出现一次的元素对应的二进制位的结果

        int ans = 0;

        for(int i = 0; i < 32; ++i)
        {
            int sum = 0;
            for(auto x : nums)
                if((x >> i) & 1) ++sum;

            sum %= 3;
            ans |= (sum << i);
        }
        return ans;
    }

2.5 只出现一次的数字 III

260. 只出现一次的数字 III

cpp 复制代码
    vector<int> singleNumber(vector<int>& nums) {
        // 假设nums中只出现一次的元素分别是x1 和 x2。
        // 将所有元素进行异或,最后剩下的只有x1^x2
        // 提取x1^x2的二进制中最右侧的1,设其为第 l 位,
        // 那么x1和x2中的某一个数的二进制表示的第 l 位为 0,
        // 另一个数的二进制表示的第 l 位为 1。
        // 这样我们可以根据元素的二进制表示的第 l 位为 0 还是 1 分成两类
        // x1 和 x2分别在这两个不同的类,最后将这两类数分别进行异或操作
        // 则可以分别得到 x1 和 x2

        // 把所有元素分为两类,一类包含x1 另一类包含x2
        int a = 0;
        for(int i = 0; i < nums.size(); ++i)
            a ^= nums[i];

        // INT_MIN取负会导致整数溢出
        int x = (a == INT_MIN ? a : a & -a);

        int x1 = 0, x2 = 0;
        for(int i = 0; i < nums.size(); ++i)
        {
            if(nums[i] & x) x1 ^= nums[i];
            else x2 ^= nums[i];
        }
        return {x1, x2};
    }

2.6 面试题 17.19. 消失的两个数字

面试题 17.19. 消失的两个数字 - 力扣(LeetCode)

根据题目2.2 和 2.5可以很轻松的解决这道题。

cpp 复制代码
    vector<int> missingTwo(vector<int>& nums) {
        int n = nums.size();
        
        int xorsum = 0;
        for(int i = 1; i <= n + 2; ++i) xorsum ^= i;

        for(auto num : nums) xorsum ^= num;
        int x = xorsum == INT_MIN ? xorsum : xorsum & (-xorsum);

        int x1 = 0, x2 = 0;
        for(int i = 1; i <= n + 2; ++i)
        {
            if(i & x) x1 ^= i;
            else x2 ^= i;

            if(i <= n)
            {
                if(nums[i - 1] & x) x1 ^= nums[i - 1];
                else x2 ^= nums[i - 1];
            }
        }

        return {x1, x2};
    }
相关推荐
QuantumStack18 分钟前
【C++ 真题】P1104 生日
开发语言·c++·算法
天若有情67329 分钟前
01_软件卓越之道:功能性与需求满足
c++·软件工程·软件
whoarethenext34 分钟前
使用 C++/OpenCV 和 MFCC 构建双重认证智能门禁系统
开发语言·c++·opencv·mfcc
代码的奴隶(艾伦·耶格尔)1 小时前
后端快捷代码
java·开发语言
Jay_5152 小时前
C++多态与虚函数详解:从入门到精通
开发语言·c++
路来了2 小时前
Python小工具之PDF合并
开发语言·windows·python
xiaolang_8616_wjl3 小时前
c++文字游戏_闯关打怪
开发语言·数据结构·c++·算法·c++20
WJ.Polar3 小时前
Python数据容器-list和tuple
开发语言·python
FrostedLotus·霜莲3 小时前
C++主流编辑器特点比较
开发语言·c++·编辑器
超级码.里奥.农3 小时前
零基础 “入坑” Java--- 七、数组(二)
java·开发语言