为下一章位运算算法做铺垫,知识点在C/C++文章中均出现过。
上篇文章:力扣:525.连续数组和1314.矩阵区域和(二维前缀和)
目录
[10.1 位1的个数](#10.1 位1的个数)
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.异或(^)运算的运算律
-
a ^ 0 = a
-
a ^ a = 0(消消乐)
-
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};
}
};
本章完。