劍指Offer題目10:二進制中1的個數(Java)

面試題10:請實現一個函數,輸入一個整數,輸出該數二進制表示中1的個數。例如把9表示成二進制是1001,有2位是1。所以若是輸入9,該函數輸出2。面試

牛客網OJ:二進制中1的個數bash

Basic

位運算無外乎 與、或、異或、左移和右移 5 種類型的運算。函數

使用位運算符進行運算時,整數會自動轉爲二進制形式,再進行位運算。全部位運算的題型基本都是各類類型位運算的組合。ui

注意點:整數包含正、負數。spa

負數右移須要在真空位補上1,如-1,二進制原碼爲 1000 0001,第一個位爲符號位,負數爲1,非負數爲0開頭。在計算機中,負數採用補碼來表示,-1的最終二進制表現形式爲: 絕對值取反加1,附帶上符號位。即 111 1111 加上符號位爲 1111 1111。3d

-1 >> 1 的結果是 1111 1111。code

解題思路

判斷二進制數中1的位數,能夠經過和整數 1 進行 與 運算,1&1 = 1,1&0 = 0。

1 的二進制形式爲:0000 0001

9 的二進制形式爲:0000 1001

9&1 = 0000 0001 != 0,能夠肯定最後一位是 1。
那麼此時要如何繼續往前判斷另外一個1呢?

解決方案:

將 1 左移一位,即 0000 0001 變爲 0000 0010,再判斷 9(0000 1001)的第 2 位
0000 0010 & 0000 1001 = 0000 0000 == 0,能夠肯定第 2 位爲 0。

這個過程當中,使用一箇中間計數器變量 count 每次肯定與運算結果爲非 0, 則加 1 便可統計 1 的個數。

再將 1 左移一位,即 0000 0010 變爲 0000 0100,再判斷 9(0000 1001)的第 3 位
0000 0100 & 0000 1001 = 0000 0100 != 0,能夠肯定第 3 位爲 1。

後面同上,1 挨個左移,直到移動到最左邊,變成 0000 0000,宣告位遍歷結束:

0000 0001
0000 0010
0000 0100
0000 1000
0001 0000
0010 0000
0100 0000
1000 0000

0000 0000 結束
複製代碼

代碼實現

public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        int flag = 1;
        while(flag != 0){
            if((n&flag) != 0){
                count++;
            }
            flag = flag << 1;
        }
        return count;
    }
}
複製代碼

總結

位運算的題首先要想到位移運算和 與或 運算的結合。cdn

擴展

擴展題目1:用一條語句判斷一個整數是否是2的整數次方。

Basic

一個整數若是是2的整數次方,那麼它的二進制表示中有且只有一位是1,而其餘全部位都是0。blog

思路分析

方案:把這個整數減去1以後再和它本身作與運算,這個整數中惟一的1就會變成0。

好比 8 的二進制位 0000 1000,0000 1000 - 1 = 0000 1000 - 0000 0001 = 0000 0111

而後再將計算結果和 8 自身進行與運算:0000 1000 & 0000 0111 = 0000 0000 結果恰好是 0 。
複製代碼

代碼實現

if((n - 1) & n == 0){
    //是2的整數次方
}
複製代碼

擴展題目2:輸入兩個整數 m 和 n,計算須要改變 m 的二進制表示中的多少位才能獲得 n。

好比 10 的二進制表示爲 1010,13 的二進制表示爲 1101,須要改變 1010 中的 3 位才能獲得 1101。get

思路分析

咱們能夠分爲兩步解決這個問題:第一步求這兩個數的異或,第二步統計異或結果中1的位數。

1010 ^ 1101 = 0111

再運用移位運算 + 與運算判斷 1 的個數。
複製代碼

代碼實現

public int numOfBitToChange(int m, int n) {
        int result = m ^ n;
        int count = 0;
        int flag = 1;
        while(flag != 0) {
            if((result & flag) != 0) {
                count ++;
            }
            flag << 1;
        }
        return count;
    }
複製代碼

觸類旁通

把一個整數減去1以後再和原來的整數作位與運算,獲得的結果至關因而把整數的二進制表示中的最右邊一個1變成0。

5 - 1 = 0101 - 0001 = 0100

0101 & 0100 = 0100 (最右邊的 1 變成0:0101 --> 0100)

4 - 1 = 0100 - 0001 = 0011

0100 & 0011 = 0000 (最右邊的 1 變成0:0100 --> 0000)

10 - 1 = 1010 - 0001 = 1001

1010 & 1001 = 1000 (最右邊的 1 變成0:1010 --> 1000)
複製代碼

不少二進制的問題均可以用這個思路解決。

相關文章
相關標籤/搜索