題目描述
請實現一個函數,輸入一個整數,輸出該數二進制表示中 1 的個數。例如,把 9 表示成二進制是 1001,有 2 位是 1。因此,如果輸入 9,則該函數輸出 2。
示例 1:
-
輸入:00000000000000000000000000001011
-
輸出:3
-
解釋:輸入的二進制串 00000000000000000000000000001011 中,共有三位爲 ‘1’。
示例 2:
-
輸入:11111111111111111111111111111101
-
輸出:31
解釋:輸入的二進制串 11111111111111111111111111111101 中,共有 31 位爲 ‘1’。
解題思路
思路一: 逐位判斷
解法一:按位與
作者:jyd
按位與運算符 &
參加運算的兩個數據,按二進制位進行與運算
- 運算規則:0&0=0;0&1=0;1&0=0;1&1=1;
根據與運算定義,設二進制數字n,則有:
-
若 n & 1 = 0,則二進制最後一位爲0;
-
若n & 1 = 1 ,則二進制最後一位 爲 1
可能會有一些小困惑,爲什麼9 & 1 = 1
,10 & 1 = 0
?數字在計算機存的是補碼,而按位與是相同爲1,不同爲0。和1
與完之後,源數字的二進制位並沒有發生變化(如果是|
就變了),因此,我們只需要逐位縮短判斷即可!
根據以上特點,考慮以下循環判斷
-
判斷n最後一位是否爲1,根據結果計數。
-
將n右移一位(本題要求把數字n看作無符號數,因此使用無符號右移操作)
算法流程
-
初始化數量統計變量res = 0
-
循環逐位判斷:當n = 0時跳出
-
res += n & 1;
若n & 1 = 1,則統計數res加。 -
n >>= 1;
將二進制數字n無符號右移位(Java中無符號右移爲>>>
)
-
-
返回統計數量res
public static int hammingWeight(int n) {
int count = 0;
while(n != 0) {
if((n & 1) != 0) {
count++;
}
n = n >>> 1;
}
return count;
}
解法二:字符比較
將數字轉換爲二進制的字符串,拿到每一位和字符1
作比較
-
讀取字符串的每一位
charAt()
【無解】 -
轉換爲字符數組(浪費空間,空間複雜度爲O(n))
踩坑:
將給定的二進制數00000000000000000000000000001011轉換爲字符串時,會出現問題
int n = 00000000000000000000000000001011;
String str = n + "";
打印str爲:521。由於我比較菜,還不知道爲什麼是這樣?知道的大佬告知一下哈!
思路二:巧用 n & (n−1)
作者:jyd (圖片來自大佬的題解,爲了能夠看懂我搬來了)
- (n−1) 解析: 二進制數字 n 最右邊的 1 變成 0 ,此 1 右邊的 0 都變成 1
- n&(n−1) 解析: 二進制數字 n 最右邊的 1 變成 0 ,其餘不變
算法流程
- 初始化數量統計變量res
- 循環消去最右邊的1:當=0時跳出
- res+=1:統計變量加1;
- n&=n-1:消去數字n最右邊的1。
- 返回統計數量res
public static int hammingWeight(int n) {
int count = 0;
while(n != 0) {
count++;
n &= n - 1;
}
return count;
}
思路三:使用Integer類提供的方法
解法一:toBinaryString()
【toBinaryString()方法分析】
- 以二進制(基數 2)無符號整數形式返回一個整數參數的字符串表示形式。
- 如果參數爲負,該無符號整數值爲參數加上 2^32;否則等於該參數。
因爲Java裏的int是有符號的,在內存中沒有正負之分,只有0/1,整數是用補碼錶示的
正數補碼等於原碼
負數的補碼等於其絕對值的反碼+1,正好等於自身+2^32(對於4字節的整型來說)
-1
的補碼 就是 絕對值1
的反碼(按位取反) `11111111 11111111 11111111 11111110
再+1
,等於
11111111 11111111 11111111 11111111
這樣正好能把最高位爲1的數字用來表示負數,而最高位爲0的數字表示非負數
10000000 00000000 00000000 00000000 => -2147483648
11111111 11111111 11111111 11111111 => -1
00000000 00000000 00000000 00000000 => 0
00000000 00000000 00000000 00000001 => 1
01111111 11111111 11111111 11111111 => 2147483647
因此負數+2^32
之後的二進制串,就是該負數內存中準確的存儲形式
此題只是針對無符號數
Integer.toBinaryString(n).replaceAll("0", "").length();
把一個10進制數轉爲32位的2進制數,將0替換爲空字符返回
解法二:bitCount()
Integer.bitCount(n)
統計二進制數中 1 的個數
此方法的源碼:
此方法的源碼分析參考文章:Integer.bitCount()理解