《劍指Offer》面試題15. 二進制中 1 的個數

題目描述

面試題15. 二進制中1的個數

請實現一個函數,輸入一個整數,輸出該數二進制表示中 1 的個數。例如,把 9 表示成二進制是 1001,有 2 位是 1。因此,如果輸入 9,則該函數輸出 2。

示例 1:

  • 輸入:00000000000000000000000000001011

  • 輸出:3

  • 解釋:輸入的二進制串 00000000000000000000000000001011 中,共有三位爲 ‘1’。

示例 2:

  • 輸入:11111111111111111111111111111101

  • 輸出:31

解釋:輸入的二進制串 11111111111111111111111111111101 中,共有 31 位爲 ‘1’。

解題思路

思路一: 逐位判斷

解法一:按位與

作者:jyd

來源:力扣(LeetCode)

按位與運算符 &

參加運算的兩個數據,按二進制位進行運算

  • 運算規則:0&0=0;0&1=0;1&0=0;1&1=1;

根據運算定義,設二進制數字n,則有:

  • 若 n & 1 = 0,則二進制最後一位爲0;

  • 若n & 1 = 1 ,則二進制最後一位 爲 1

可能會有一些小困惑,爲什麼9 & 1 = 110 & 1 = 0?數字在計算機存的是補碼,而按位與是相同爲1,不同爲0。和1與完之後,源數字的二進制位並沒有發生變化(如果是|就變了),因此,我們只需要逐位縮短判斷即可!


根據以上特點,考慮以下循環判斷

  1. 判斷n最後一位是否爲1,根據結果計數。

  2. 將n右移一位(本題要求把數字n看作無符號數,因此使用無符號右移操作)

算法流程

  1. 初始化數量統計變量res = 0

  2. 循環逐位判斷:當n = 0時跳出

    • res += n & 1; 若n & 1 = 1,則統計數res加。

    • n >>= 1;將二進制數字n無符號右移位(Java中無符號右移爲>>>

  3. 返回統計數量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)

  • (n−1) 解析: 二進制數字 n 最右邊的 1 變成 0 ,此 1 右邊的 0 都變成 1
  • n&(n−1) 解析: 二進制數字 n 最右邊的 1 變成 0 ,其餘不變

算法流程

  1. 初始化數量統計變量res
  2. 循環消去最右邊的1:當=0時跳出
    • res+=1:統計變量加1;
    • n&=n-1:消去數字n最右邊的1。
  3. 返回統計數量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()理解

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章