常见位运算基础知识,技巧总结以及力扣实战

为下一章位运算算法做铺垫,知识点在C/C++文章中均出现过。

上篇文章:力扣:525.连续数组和1314.矩阵区域和(二维前缀和)

目录

1.基础位运算

2.位运算优先级

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

4.将一个数n的二进制表示的第x位修改为1

5.将一个数n的二进制表示的第x位修改为0

6.位图的思想

7.提取一个数(n)二进制表示最右侧的1

8.去掉一个数(n)二进制表示中最右侧的1

9.异或(^)运算的运算律

10.相关力扣算法题

[10.1 位1的个数](#10.1 位1的个数)

10.2比特位计数

10.3汉明距离

10.4只出现一次的数字

10.5只出现一次的数字


1.基础位运算

<< :按位左移运算符,将数值的二进制位整体向左移动指定的位数,右侧低位统一补 0,左侧高位超出存储位数的部分直接丢弃

>> :按位右移运算符,分为算术右移(带符号右移)和逻辑右移(无符号右移)。

算术右移(大多数语言有符号数的默认右移规则):将数值的二进制位整体向右移动指定的位数,左侧高位统一补「符号位」(正数补 0,负数补 1),右侧低位超出的部分直接丢弃

逻辑右移:将数值的二进制位整体向右移动指定的位数,无论正负,左侧高位统一补 0,右侧低位超出的部分直接丢弃

~ :按位取反

& :按位与,有0就是0

| :按位或,有1就是1

&与| 举例:

0 1 0

0 1 1


& 0 1 0

^ 0 1 1

^ :按位异或,或称为 无进位相加。相同为0,相异为1

无进位相加举例:

0 1 0

^ 0 1 1


0 0 1

其中,1与1相加为2,进位则将其丢掉,结果变为1

2.位运算优先级

需要括号,就加括号。

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

方法:(n>>x)& 1 分两种结果:0 -> 0或 1 -> 1

举例:

n:0 1 1 0 1 0 1 0 0 1

x位

4.将一个数n的二进制表示的第x位修改为1

公式:n |= (1 << x)

举例:

x位

0 1 1 0 1 0 1 0 1 1

| 0 0 0 0 0 1 0 0 0 0


0 1 1 0 1 1 1 0 1 1

5.将一个数n的二进制表示的第x位修改为0

公式:n &= (~(1 << x))

举例:

x位

0 1 1 0 1 0 1 0 1 1

& 1 1 1 1 1 1 0 1 1 1


0 1 1 0 1 0 0 0 1 1

6.位图的思想

int[ ]数组(哈希表思路):1 个 int 类型占 32 个二进制位,却只能标记 1 个数字的状态,空间利用率极低:

位图思路:把自身 32 个二进制位拆开,每 1 位独立对应 1 个数字的状态------ 位的值为 1,代表对应数字存在 / 已标记;位的值为 0,代表对应数字不存在 / 未标记。

7.提取一个数(n)二进制表示最右侧的1

公式:n & ((~n) + 1) 或 n & (-n)

在计算机的二进制补码体系中,负数的存储规则是:-n = ~n + 1(对原数按位取反再加 1),因此 n & (~n + 1)n & -n 是完全等价的写法,后者更简洁,是工程中更常用的形式。

(-n)的意义:将最右侧的1,左边的区域全部变为相反。

举例:

0 1 1 0 1 0 1 0 0 0

~ 1 0 0 1 0 1 0 1 1 1

+1 1 0 0 1 0 1 1 0 0 0

& 0 1 1 0 1 0 1 0 0 0


0 0 0 0 0 0 1 0 0 0

8.去掉一个数(n)二进制表示中最右侧的1

公式:n & (n - 1)

(n - 1)的含义:将最右侧的1,右边的区域(包含1)全部变成相反。

举例:

n: 0 1 1 0 1 0 1 0 0

n-1: 0 1 1 0 1 0 0 1 1

&: 0 1 1 0 1 0 0 0 0


0 1 1 0 1 0 0 0 0

9.异或(^)运算的运算律

  1. a ^ 0 = a

  2. a ^ a = 0(消消乐)

  3. a ^ b ^ c = a ^ (b ^ c)

10.相关力扣算法题

10.1 位1的个数

https://leetcode.cn/problems/number-of-1-bits/

复制代码
class Solution 
{
public:
    int hammingWeight(int n) 
    {
        int count = 0;
        unsigned int num = n;
        while(num > 0)
        {
            int lowbit = num & (-num);
            count++;
            num -= lowbit;
        }
        return count;
    }
};

10.2比特位计数

https://leetcode.cn/problems/counting-bits/description/

复制代码
class Solution {
public:
    vector<int> countBits(int n) {
        vector<int> ans(n + 1, 0);
        for(int i = 0; i <= n; i++)
        {
            int num = i;
            int count = 0;
            while(num > 0)
            {
                int lowbit = num & (-num);
                count++;
                num -= lowbit;
            }
            ans[i] = count;
        }
        return ans;
    }
};

解法二:

复制代码
class Solution {
public:
    vector<int> countBits(int n) {
        vector<int> dp(n + 1, 0);
        for(int i = 1; i <= n; i++)
        {
            dp[i] = dp[i & (i - 1)] + 1;
        }
        return dp;
    }
};

10.3汉明距离

https://leetcode.cn/problems/hamming-distance/

复制代码
class Solution 
{
public:
    int hammingDistance(int x, int y) 
    {
        int count = 0;
        int diff = x ^ y;
        while(diff > 0)
        {
            int lowbit = diff & (-diff);
            count++;
            diff -= lowbit;
        }
        return count;
    }
};

10.4只出现一次的数字

https://leetcode.cn/problems/single-number/description/

复制代码
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ret = 0;
        for(int num : nums)
        {
            ret ^= num;
        }
        return ret;
    }
};

10.5只出现一次的数字

https://leetcode.cn/problems/single-number-iii/

复制代码
class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int diff = 0;
        for(int num : nums)
        {
            diff ^= num;
        }

        int lowbit = diff & (-diff);
        int a = 0, b = 0;
        for(int num : nums)
        {
            if(num & lowbit) a ^= num;
            else b ^= num;
        }
        return {a,b};
    }
};

本章完。

相关推荐
sycmancia2 小时前
C++——C++异常处理
开发语言·c++
RuiBo_Qiu2 小时前
【LLM进阶-后训练&部署】1. 大语言模型全参数微调:从前向推理到反向传播的底层原理解析
人工智能·算法·语言模型·自然语言处理·ai-native
HLC++2 小时前
C++中的类和对象
开发语言·c++
橙子也要努力变强2 小时前
Linux I/O 缓冲区、inode、软硬链接与磁盘结构全解析
linux·c++·操作系统
子有内涵2 小时前
【Linux】程序地址空间(是什么?为什么?)
linux·运维·算法
setmoon2142 小时前
C++与量子计算模拟
开发语言·c++·算法
实心儿儿2 小时前
算法6:相交链表
数据结构·算法·链表
Amnesia0_02 小时前
C++的异常
开发语言·c++·学习
nglff2 小时前
蓝桥杯抱佛脚第二天|简单枚举,前缀和
算法·职场和发展·蓝桥杯