学习内容
希望各位伙伴在刷力扣的二进制专题时,当然也是我自己的查找字典。后期在做题过程中会不定时补充,不需要左右查找,希望这个可以成为一个二进制字典~
二进制&常用知识点梳理
基础位运算
& : 按位与操作,只有两者都为1才是1
性质
归零性:0 & 任何数 = 0
保位性:1 & 任何数= 原数
单调性:执行 x & y之后,得出来得值一定 <=x 且 <= y (只会在原位保留1,而不是凭空产生1)
&简单用法
1、
判断奇偶性 ( x & 1 , 结果1 = 奇数,结果0 = 偶数 , 如果是奇数,那么其二进制位最低位必定为1 )
5 [101] & 1 [001] = 1 , 6 [110] & 1 [001] = 0 , 0 [0] & 1 [1] = 0
使用场景:判断二进制最低位是否为1、比特位计数、交替位判断
2、
检测第k位是否为1 ( x & ( 1 << k ) ), 结果非0则1
1<<k 生成第k位为1其余位为0的数(掩码),与x按位与之后,非0则第k位为1
检测6 [110] 的第2位是否为1: ( 6 & ( 1 << 2 ) ) != 0
使用场景:子集枚举、位状态判断、逐位遍历二进制数
3、提取数组指定位
构造掩码(目标位置为1,其他位置为0),与x 按位与后,清除无关位,保留目标位
提取最后8位 x & 0xff (每个16进制位 = 4个二进制位,相当于二进制的 1111 1111)
提取最后4位 x & 0x0f
保留奇数位 : x & 0x55555555 ( 32位掩码,奇数位为1 )
使用场景: 字节处理、二进制位拆分、4/8 的幂判定
4、清除数字特定位
构造掩码(目标位置为0,其他位置为1),与x 按位与后 ,目标位置0,保留位不变
x & ~ (1 << k) (清除第k位 , 其中 1 << k 表示目标位为1,其余位为0,~ 为取反)
清除6 [110] 的第一位, 6 & (~ (1 << 1))
使用场景: 位状态修改、二进制重排、状态压缩
&高阶用法
1、清除数字二进制中 最后一个1 : x & (x - 1)
6 [110] & 5 [101] = 4 [100]
5 [101] & 4 [100] = 4 [100]
使用场景: 可用来统计1的个数、2的幂判断、比特位计数
2、判定整数是否为2的幂
2的幂的二进制只有1个1, 执行 x & (x-1)之后必为0,且判断数必须排除0和负数
x > 0 && ( x & ( x - 1 ) == 0 )
使用场景:判断2的幂、交替位二进制判断
3、定位负数补码中最后一个1的位置
计算机中的负数以补码形式存储,即 -x = ~x + 1 ,x与-x 按位与会直接保留最后一个1,其余位清0
x & (-x) ,x 为非0整数,正负均适用,直接返回最后一个1的数值
-6 [1111 1010 ] & 6 [0000 0110] = 2 [0000 0010]
5 [0000 0101] & -5 [1111 1011] = 1 [0000 0001]
使用场景:快速定位1的位置、树状数组、位分组统计
4、计算二进制加法的进位(配合左移,实现无加减加法)
二进制中同时为1才会产生进位,按位先找到所有的进位位,左移1为表示实际进位值
( a & b ) << 1 (与左移相结合)
3 [0011] & 5 [0101] = 实际进位位仅为1
使用场景:两整数之和(不用加减乘除做加法)
5、判断全1二进制数 (配合 + 1)
全1的二进制数在加1之后,所有的1全变为0,最高位变为1
x & ( x + 1 ) == 0 (x > 0)
7 [0111] & 8 [1000] = 0
使用场景:交替为二进制数
6、4/8的幂判定
4的幂判定:是2的幂基础上,唯一的1在指定奇数位 x > 0 && (x & ( x - 1 ) == 0 ) && (x & 0x55555555 ) != 0
8的幂判定:是2的幂基础上,唯一的1在指定位 x > 0 && (x & ( x - 1 ) == 0 ) && (x & 0x 33333333) != 0
使用场景:判断是否4/8的幂
7、二进制状态压缩的状态判断(重点! 替代数组/哈希表)
用整数的每一个位表示一个状态(是否选中,是否出现)
判断字符串中是否有重复字符: mask & ( 1 << ( c - 'a' ) ) != 0,其他mask是记录状态整数
判断子集是否选中第k个元素:mask & (1 << k ) != 0 (mask为状态压缩数)
空间复杂度从O(n)降到O(1)
使用场景:找不同、找重复数字或字符、选中子集、最大单词长度乘积
& 避坑操作
1、优先级问题
&的优先级低于算术运算、逻辑运算,如果混合运算必须加括号
2、负数处理
负数以补码形式存储,&对负数直接按补码运算,遍历负数时需强转无符号或用无符号右移,避免死循环
3、溢出问题
配合左移<<时,需要用long long / long 来接收结果,或强转无符号,避免溢出
4、边界判断
2/4幂判定中,必须加x > 0 ,否则和负数会误判