位运算
从集合论到位运算,常见位运算技巧分类总结! - 力扣(LeetCode)
位运算
常用的位运算符号包括:^按位异或,&按位与,|按位或,~取反,<<算术左移,>>算术右移
x^0=x | x&0=0 | x|0=x |
---|---|---|
x^1s=~x | x&1s=x | x|1s=1 |
x^x=0 | x&x=x | x|x=x |
作用 | 操作 | 示例 |
---|---|---|
去除n的二进制表示中最低的一位 | n&(n-1) | 11010&(11001)=11000 |
得到n的二进制表示中最低的一位 | n&(-n) | 11010&(00110)=00010 |
低位清0:[0:n]位清0 | x & ~( (1<<(n+1)) -1 ) | |
取反第n位 | x^(1<<n) | |
c++位运算函数 | ||
n的二进制表示中有多少个1 | __builtin_popcount(n) |
异或
-
$x\oplus x=0$
-
$x\oplus 0=x$
-
$x\oplus y=y\oplus x$
-
$x\oplus y\oplus y=x$
-
$x\oplus y=z\Longrightarrow x\oplus z=y$
x | x | 结果 |
---|---|---|
x&(-x)(得到最低位的1) | x=16(10000) | 10000 |
x&(x-1)(最低位1变为0) | 17(10001) | 10000 |
位运算基础知识
-
判断奇偶:
-
奇:
(x & 1) == 1
⟺ if⟺(x & 1) != 0
-
偶:
(x & 1) == 0
⟺ \iff⟺(x & 1) != 1
-
-
乘(或除)以 2 的幂次:
-
x >> n
⟺ iff⟺x / 2^n
-
x << n
⟺ \iff⟺x * 2^n
-
-
去除最后一位 1:
x & (x - 1)
-
得到最后一位 1:
x & -x
-
判断 2 的幂次:
x & (x - 1) == 0
-
交换两个数:
a ^= b; b ^= a; a ^= b;
-
交换符号:
~x + 1
⟺ \iff⟺-x
-
取绝对值:
(x ^ x >> size(x) - 1) - (x >> size(x) - 1)
⟺ \iff⟺x < 0 ? -x : x
-
构造 n 个 1:
(1 << n) - 1
-
将最左边的 n 位清零:
x & (~0 << n)
-
获取 x 的第 n 位值(0 或 1):
(x >> n) & 1
-
获取 x 的第 n 位的幂值:
x & (1 << n)
-
仅将第 n 位置为 1:
x | (1 << n)
-
仅将第 n 位置为 0:
x & (~(1 << n))
-
将 x 最高位至第 n 位(含)清零:
x & ((1 << n) - 1)
-
将第 n 位至第 0 位(含)清零:
x & (~((1 << (n + 1)) - 1))
-
异或满足交换律、结合律:
a ^ b ^ a = b ^ (a ^ a) = b ^ 0 = b
面试题 05.01. 插入 - 力扣(LeetCode)
得到二进制数x最低位的1(lowbit)
x&-x
负数按照补码规则在计算机中存储,-n的二进制表示为n的二进制表示的每一位取反加1(包括符号位)
二进制数最低位的1变成0
x=x&(x-1)
x-=(x&-x)
将二进制数x最低位的0变成1
x取反的最低位1是x的最低位0
y=~x
x|=y&(-y)
x=x| (x+1)
二进制特性
可以利用二进制和位运算输出一个数组的所有子集。假设有一个长度为n的数组,可以生成长度为n的所有二进制,1表示选取该数字,0表示不选取,可以得到$2^n$个子集。快速判断两个字符串是否含有重复字母:为每个字符串建立一个长度为26的二进制数字,每个位置表示是否存在该字母
位计数(统计1的数目)
cnt=0 |
Brian Kernighan算法
对于任意整数 xx,令 x=x & (x−1),该运算将 x 的二进制表示的最后一个 1 变成 0。因此,对 x 重复该操作,直到 x 变成 0,则操作次数即为 x 的「一比特数」。
对于给定的 n,计算从 0 到 n 的每个整数的「一比特数」的时间都不会超过O(logn),因此总时间复杂度为O(nlogn)。
c(x)表示二进制表示x中的1个数
c(x&y)+c(x|y)=c(x)+c(y)
题目
异或
分享|异或/XOR部分问题汇总 - 力扣(LeetCode)
题目 | 标签 |
---|---|
421. 数组中两个数的最大异或值 - 力扣(LeetCode) | 字典树 |
1720. 解码异或后的数组 - 力扣(LeetCode) | 数学 |
1734. 解码异或后的排列 - 力扣(LeetCode) | 数学 |
1863. 找出所有子集的异或总和再求和 - 力扣(LeetCode) | 枚举子集(二进制状态枚举,递归枚举) |
1310. 子数组异或查询 - 力扣(LeetCode) | 异或前缀和 |
1829. 每个查询的最大异或值 - 力扣(LeetCode) | 前缀异或和、异或最大值、技巧 |
268. 丢失的数字 - 力扣(LeetCode) | 异或,非常巧妙,单一的数字变种题 |
$$ |
\begin{align}
&1734题\\
&(a,b,c,d,e)\\
&(x,y,z,w)\\
&\text{有5个数字}:y\oplus w=b\oplus c\oplus d\oplus e=p\\
&a\oplus b\oplus c\oplus d\oplus e=1\oplus 2\oplus 3\oplus 4\oplus 5=q\\
&a=q\oplus(b\oplus c\oplus d\oplus e)=q\oplus p
&\end{align}
$$