什麼是位運算
現代計算機中所有的資料都是以二進位制的形式儲存在計算機中的儲存設定中,即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