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

为下一章位运算算法做铺垫,知识点在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};
    }
};

本章完。

相关推荐
Dlrb12118 小时前
C语言-指针三
c语言·算法·指针·const·命令行参数
Tisfy8 小时前
LeetCode 2540.最小公共值:双指针(O(m+n))
算法·leetcode·题解·双指针
IronMurphy8 小时前
【算法四十七】152. 乘积最大子数组
算法
REDcker9 小时前
有限状态机与状态模式详解 FSM建模Java状态模式与C++表驱动模板实践
java·c++·状态模式
basketball6169 小时前
C++ 构造函数完全指南:从入门到进阶
java·开发语言·c++
淘矿人10 小时前
Claude辅助DevOps实践
java·大数据·运维·人工智能·算法·bug·devops
Cosolar10 小时前
万字详解:RAG 向量索引算法与向量数据库架构及实战
数据库·人工智能·算法·数据库架构·milvus
想唱rap10 小时前
IO多路转接之poll
服务器·开发语言·数据库·c++
小江的记录本10 小时前
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
java·数据结构·后端·mysql·spring·面试·职场和发展