目录
妙用位运算
知识简介
bit是度量信息的单位,包含0和1两种状态。
计算机的各种运算最后无不归结为一个个
bit
的变化。熟练掌握并利用位运算,能够帮助我们理解程序运行中的种种表现,提高程序运行时的时空效率,降低编程复杂度。
与 | 或 | 非 | 异或 | 左移 | 算术右移 |
---|---|---|---|---|---|
& | | | ! | nor | << | >> |
5&3=1 | 5|3=7 | ~5=2,~3=4 | 5^3=6 | 5<<1=10 | 5>>1=2 |
(注:此处为了与次幂区别开,本篇中异或均写为nor
,但在实际使用中以^
为准)
移位运算
左移
在二进制表示下把数字同时向左移动,地位以0填充,高位越界后舍弃。
1 << n = 2^n n << 1 = 2n
算术右移
在二进制补码表示下把数字向右移动,高位以符号位填充,低位越界后舍弃。
算术右移等于除以2向下取整。
(-3)>>1 = -2 3>>1 =1
此处与整除运算有所区别,”整数/2“实现为 “除以2向0取整”,
(-3) / 2 = -1 3/2 = 1
补码
无符号数:直接把该32为编码
C
看作32位二进制数N有符号数:以最高为为符号位,0为正,1为负
正数的补码均为它本身,负数的补码为编码
C
按位取反加1。注:计算机使用补码进行各种加减乘除运算,补码可以保证每个数值都有唯一的表示方式。(此篇以
C++
为准,Java
中没有无符号数)
应用
快速幂
例:
a^b
, 求a
的b
次方对p
取模的值,其中1<=a,b,p
<=10^9。根据数学尝试,每一个正整数可以唯一表示为若干指数不重复的2的次幂的和。也就是说如果
b
在二进制表示下有k为,其中第i(0<=i<k)
位的数字是Ci
,那么就有:于是就有:
因为
k=[log2(b+1)]
([]为向上取整),所以上式乘积项的数量不多于[log2(b+1)]
个。又因为:所以我们很容易通过
k
次地推求出每个乘积项。
当
b
中乘积项的系数为1时,把该乘积项累积到答案中。
b&1
运算可以取出b在二进制表示下的最低位,而b>>1
运算可以舍去最低位,在递推过程中就可以遍历b
中每个乘积项的系数。时间复杂度
O(log2b)
代码
int power ( int a, int b, int p){
int res = 1 ;
while( b != 0){
if(b & 1 == 1){
res = (long)res * a % p; //如果系数为1,乘进结果里
}
a = (long)a * a % p; //计算第k位对应的指数a
b >>= 1; //右移一位舍去最低位
}
return res;
}
练习
看完以上快速幂的神奇运算,你是不是惊讶到了呢。
快来趁热打铁练习练习吧。
例:
求
a
乘b
对p
取模的值,其中1<=a,b,p
<=10^18。
lowbit运算
lowbit(n)
定义为非负整数n
在二进制表示下“最低为的1及起后边所有的0”构成的数值。例如n=10
的二进制表示位(1010)2
,则lowbit(n)=2=(10)2
。推导公式:
设
n>0
,n
的第k
位是1
,第0~k-1
位都是0
。为了实现lowbit运算,先把
n
取反,此时第k
位变为0
,第第0~k-1
位都是1
。再令n=n+1
,此时因为进位,第k
位变为1
,第0~k-1
位都是0
。在上面的取反加
1
操作后,n&(~n+1)
仅有第k
位为1
,其余位0
。而上文中提到补码-n = ~n+1
,因此有:
妙用lowbit
lowbit
运算可以找出整数二进制表示下为1
的位数,且时间复杂度为O(1)
。我们只需不断把
n
赋值为n - lowbit(n)
,直至n=0
例: n = 9 =(1001)2 则 lowbit(n) =1,把n赋值为 n - lowbit(n)
即为 9- lowbit(9) = 8 =(1000)2 则lowbit(8) = 8 =(1000)2,此时n=0。
状态压缩
二进制状态压缩,是指将一个长度为m的bool数组用一个m位二进制整数并存储的方法。利用下列位运算操作可以实现原bool数组对应下标元素的存取。
操作 | 运算 |
---|---|
取出整数n在二进制表示下的第k位 | (n>>k) & 1 |
取出整数n在二进制表示下的第0~k-1位(后k位) | n & ((1<<k)-1) |
把整数n在二进制表示下的第k位取反 | n xor (1<<k) |
对整数n在二进制表示下的第k位赋值1 | n | (1<<k) |
对整数n在二进制表示下的第k位赋值1 | n & (~(1<<k)) |
补充
怎么样,看完了本文章是不是感觉功力大增呢,快去leetcode做一做练习修炼一下内功。
今天很开心,因为解锁了leetcode题数破百成就哦。快来跟我一起竞争吧!!
中等题的数量还很少,还要继续加油呀!
刷题之路,任重而道远。