1. 程式人生 > >整數的二進位制中1的個數

整數的二進位制中1的個數

題:輸入一個整數,輸出該數二進位制表示中1的個數。其中負數用補碼錶示。

思路1:對於輸入的整數n,判斷它的二進位制表示的最右邊是否為1,然後將n右移一位,直到n為0,就可以得出整數n的二進位制表示中1的個數。怎麼判斷二進位制表示的最右邊是否為1呢,拿n與1做與運算,因為1的二進位制表示為0001,所以,如果n的二進位制表示的最右邊為1,那麼與運算的結果就是1。

程式碼:

public int NumberOf1(int n) {
        if(n == 0)
            return 0;

        int count = 0;
        while(n != 0){
            if
((n & 1) == 1) count++; n = n >> 1; } return count; }

這種解法,看似很完美,但是當輸入的整數為負數的時候,程式就會陷入死迴圈。因為當輸入的數為負數時,當將n右移的時候,最高位補的就不是0了而是1,這樣n就一直不會等於0,也就是進入了死迴圈。

思路2:在上面的思路的基礎下,換一個方位來想。我們不動n,而是動和n做與運算的1。令1=i,我們在每一次做與運算後,讓i往左移1位,這樣就相當於輪詢n的二進位制表示的每一位。因為1不管怎麼向左移,它的二進位制表示裡始終就只有一個1。所以如果n與i相與的結果不為0或者說等於i,那麼就表示n的二進位制表示裡這一位上面是1。

程式碼:

public int NumberOf1(int n) {
        if(n == 0)
            return 0;

        int count = 0;
        int i = 1;
        while(i != 0){
            if((n & i) == i)
                count++;
            i = i << 1;
        }

        return count;
    }

這種思路,就不會導致上面的死迴圈,因為我們根本沒動n,所以這段程式碼是可以通過的,但它不是最優的。

最優思路:如果整數n不為0,那麼n的二進位制表示裡至少有一位是1。如果我們把n減去1,那麼原來處在n的二進位制表示的最右邊的1就會變成0,原來在1後面的所有的0都會變成1。其餘的所有位將不受到影響。舉個例子:一個二進位制數1100,從右邊數起的第三位是處於最右邊的一個1。減去1後,第三位變成0,它後面的兩位0變成1,而前面的1保持不變,因此得到結果是1011。
可以發現減1的結果是把從最右邊一個1開始的所有位都取反了。這個時候如果我們再把原來的整數和減去1之後的結果做與運算,從原來整數最右邊一個1那一位開始所有位都會變成0。如1100&1011=1000。也就是說,把一個整數減去1,再和原整數做與運算,會把該整數最右邊一個1變成0。那麼一個整數的二進位制有多少個1,就可以進行多少次這樣的操作。

程式碼:

public int NumberOf1(int n) {
        if(n == 0)
            return 0;

        int count = 0;
        while(n != 0){
            count++;
            n = n & (n-1);
        }

        return count;
    }

嘔心瀝血寫出來的,轉載請一定註明出處!