什么是位运算
现代计算机中所有的数据都是以二进制的形式存储在计算机中的存储设置中,即0、1两种形态,对计算机的各个操作对应的是二进制数据的各种运算。
运算符
符号 | 描述 | 运算规则 |
---|---|---|
& | 与,两个位都为1时,结果才为1 | 1&1=1 1&0=0 0&0=0 |
| | 或,两个位都为0时,结果才为0 | 1|1=1 1|0=1 0|0=0 |
^ | 异或,两个位相同为0,相异为1 | 1^1=0 1^0=0 0^1=0 0^0=0 |
~ | 取反,0变1,1变0 | ~1=0 ~0=1 |
>> | 右移 | |
<< | 左移 |
与
两个位都为1时,结果才为1
基础运算
0 & 1 = 0
1 & 0 = 0
0 & 0 = 0
1 & 1 = 1
与运算的用途
判断奇偶
偶数的二进制位的末位为0,奇数的末位为1,根据1&1=1,1&0=0可以判断奇偶
if a&1==0://
偶数
else:
奇数
判断一个数是否为2的整数幂
如果一个数是2的整数幂,则二进制1左移n位得到的,也就是2的整数幂只有最高位是1,其他位都是0,如果与一个高位为0其他位都是1的数进行&
运算,则结果为0,高们为0,其余位为1的数为数字-1
的结果,即num&(num-1)
def isPowerOf2(n):
return n&(n-1)
二进制中1的个数
def num_1(n):
i=0
while n>0:
n=n&(n-1)
i+=1
return n
或
参加运算的两个对象只要有一个为1,其值为1
基础运算
0|0=0
0|1=1
1|0=1
1|1=1
或运算的用途
融合
异或
参加运算的两个对象,如果两个相应位相同为0,相异为1。不进位的加法。
基础运算
0^0=0
0^1=1
1^0=1
1^1=0
异或运算的用途
交换两个数
x=x^y
y=x^y
x=x^y
任何数异或自己=把自己置0
快速判断两个值是否相等
return ((a ^ b) == 0)
相关例题
191.位1的个数
编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为汉明重量)。
提示:
请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 3 中,输入表示有符号整数 -3。
示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
提示:
输入必须是长度为 32 的 二进制串 。
假如十进制5,有多少个十进制1组成,那就进行逐步减1操作,直到数字减为0。
而二进制的操作也是类似的,二进制减1后,则最后一个1会变成0,减1二进制前半部分还要参与下次的运算,后半部分则要舍掉。
代码
class Solution(object):
def hammingWeight(self, n):
res=0
while n>0:
n&=(n-1)
res+=1
return res
231.2的幂
给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。
如果存在一个整数 x 使得 n == 2x ,则认为 n 是 2 的幂次方。
示例 1:
输入:n = 1
输出:true
解释:20 = 1
示例 2:
输入:n = 16
输出:true
解释:24 = 16
示例 3:
输入:n = 3
输出:false
示例 4:
输入:n = 4
输出:true
示例 5:
输入:n = 5
输出:false
提示:
-2^31 <= n <= 2^31 - 1
代码
class Solution(object):
def isPowerOfTwo(self, n):
return n>0 and n&(n-1)==0
190.颠倒二进制位
颠倒给定的 32 位无符号整数的二进制位。
提示:
请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在上面的 示例 2 中,输入表示有符号整数 -3,输出表示有符号整数 -1073741825。
示例 1:
输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000
解释: 输入的二进制串 00000010100101000001111010011100 表示无符号整数 43261596,
因此返回 964176192,其二进制表示形式为 00111001011110000010100101000000。
示例 2:
输入:11111111111111111111111111111101
输出:10111111111111111111111111111111
解释:输入的二进制串 11111111111111111111111111111101 表示无符号整数 4294967293,
因此返回 3221225471 其二进制表示形式为 10111111111111111111111111111111 。
提示:
输入是一个长度为 32 的二进制字符串
根据n&1
可以获取最后一个二进制数字
截取二进制串的最后一位,然后左移[32..1]位,保存到res
中,然后字符在右移1位,继续上面的运行
res=0
n=00000010100101000001111010011100
i=0 时,截取最后一位
00000010100101000001111010011100 & 1
=0
截取的0
左移32位,'res=0<<32',然后字符串在右移1位置
n=00000010100101000001111010011100>>1
n=0000001010010100000111101001110
i=1时,截取最后一位
0000001010010100000111101001110&1
=0
截取的0
左移31位,'0<<31' 在与res进行合并操作,res=res|(0<<31)
然后字符串在右移1位置
n=0000001010010100000111101001110>>1
n=000000101001010000011110100111
....
以此类推,知道n=0或i=31
class Solution:
def reverseBits(self, n):
res=0
for i in range(32):
if n==0:
break
# print(bin(n),n&1,n|0)
res|=(n&1)<<(31-i)
n>>=1
return res
338.比特位计数
给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。
示例 1:
输入: 2
输出: [0,1,1]
示例 2:
输入: 5
输出: [0,1,1,2,1,2]
二进制中,末位为1的是奇数,末位是0的为偶数,奇数的1的个数,比上个偶数的1的个数多1
所以,如果一个数是奇数时,奇数一定比前面那个偶数多一个 1
如果是偶数时,因为偶数末位是0,所以右移1位的1的个数与此数1的个数是相等的,
例:12
12=1100
6=110
3=11
例:8
8=1000
4=100
2=10
1=1
所以可以推到出这样的DP公式
f(n)=f(n>>1) n为偶数(n>0)
f(n)=f(n-1)+1 n为奇数时(n>1)
f(0)=0
代码如下
class Solution(object):
def countBits(self, num):
dp=[0]*(num+1)
dp[0]=0
for i in range(1,num+1):
# print(dp)
if i&1==0:
dp[i]=dp[i>>1]
else:
dp[i]=dp[i-1]+1
return dp