1. 題目
- 編寫一個函數,輸入無符號整數,返回二進制表達式中的數字位數爲’1’的個數,也稱爲漢明重量:https://leetcode-cn.com/problems/number-of-1-bits/
- 給定一個整數,編寫一個函數欄判斷它是否是2的冪次方:https://leetcode-cn.com/problems/power-of-two/
- 比特位計數:給定一個非負整數num,對於0<=i<=num範圍中的每個數字i,計算其二進制數中的1的數目並將它們作爲數組返回:https://leetcode-cn.com/problems/counting-bits/
2. 基本知識
2.1 位運算介紹
計算機是用二進制存儲和計算的,直接使用二進制進行運算,那麼效率會高很多。
10進制轉換爲二進制:10進制的數除以2取餘,再用得到的商除以2再取餘,一直循環到商爲0,然後將餘數按高位到低位排列起來就是二進制數。
6的二進制:110
2.2 位運算常用的操作
- & : 與,兩個位都爲1,結果才爲1
- | : 或,兩個位都爲0,結果才爲0
- ^ : 異或,兩個位相同爲0,相異爲1
- ~ : 取反,0變1,1變0
- << : 左移,各二進制位全部左移若干位,低位補0
-
: 右移,各二進制位全部右移若干位,無符號數,高位補0;有符號數,各編譯器處理方法不一,有的補符號位(算術右移),有的補0(邏輯右移)
2.3 位運算的應用
2.3.1 異或
x ^ 0 = x 和0做異或運算,x不變
x ^ 1s = ~x ,1s表示位數全爲1的數,任何數和1進行異或運算都是取反
x ^ (~x) = 1s
x ^ x = 0 因爲每個位數都一樣,所以得0
兩個數交換
常規寫法:
int temp = x;
x = y;
y = temp;
使用異或:
x = x ^ y; // ①
y = x ^ y; // ②
x = x ^ y; // ③
拆解一下(異或支持交換律和結合律的):
- ①是初始條件
- ②拆解爲:y = (x ^ y) ^ y = x^ (y ^ y) = x ^ 0 = x
- ③拆解爲:x = (x ^ y) ^ x = (x ^ x) ^ y = 0 ^ y = y
2,3,2 與運算
x = x &(x - 1) //清零最低位的1
x & -x // 可以得到最低位的1(並不一定是最後一位)
判斷奇偶
%2寫法:
x % 2 //結果爲1,則x是奇數,結果爲0,則x是偶數
與運算寫法:
x & 1 //結果爲1,則x是奇數,結果爲0,則x是偶數
與運算解法拆解一下,6&1=> 110&001,前面的位數不管是0還是1,和0做&運算都是0,則結果爲最後一位和1做&運算,得到如上的結果。
3. 算法題解
3.1 編寫一個函數,輸入無符號整數,返回二進制表達式中的數字位數爲’1’的個數,也稱爲漢明重量
解法1:判斷最後一位奇偶,然後左移一位,直到爲0
該解法時間複雜度爲O(1)(常數次循環),空間複雜度爲O(1)
private int hanmingWeight(int n) {
int sum = 0;
while (n != 0) {
if ((n & 1) == 1) {
sum++;
}
n <<= 1;
}
return sum;
}
解法2:通過x & (x-1)這個公式,可以把最後一位1置爲0,不斷循環直到n爲0
該解法時間複雜度和空間複雜度都爲O(1)
private int hanmingWeight(int n) {
int sum = 0;
while (n != 0) {
n &= (n - 1);
sum++;
}
return sum;
}
3.2 給定一個整數,編寫一個函數欄判斷它是否是2的冪次方
2的冪次方有一個特點,換成二進制時,所有的位數值只有一個是1,其他爲0,而x & (x-1)這個公式可以將最後一個1清零,則有以下的解法。
private boolean isPowerOfTwo(int n) {
return n > 0 & (n & (n - 1)) == 0;
}
3.3 比特位計數
給定一個非負整數num,對於0<=i<=num範圍中的每個數字i,計算其二進制數中的1的數目並將它們作爲數組返回
解法1 :循環每個數,找到每個數中1的個數
使用了漢明重量的算法
private int[] countBits(int num) {
int[] result = new int[num];
for (int i = 0; i < num; i++) {
int resultI = hanmingWeight(i);
result[i] = resultI;
}
return result;
}
解法2:
還是用到這個公式:x & (x-1),這個公式可以將最後一個1清零,那麼x = x & (x-1) + 1,延伸出來就是 第i個數的1的個數爲:count【i】 = count【i & (i - 1)】 + 1(因爲i&*(i-1)只去掉最後一個1)
private int[] countBis(int num) {
int[] result = new int[num];
result[0] = 0;
for (int i = 1; i < num; i++) {
result[i] = result[i & (i - 1)] + 1;
}
return result;
}