1. 程式人生 > >位運算:二進位制中1的個數

位運算:二進位制中1的個數

題目:請實現一個函式,輸入一個整數,輸出該數二進位制表示中1的個數。例如把9表示成二進位制是1001,有2位是1。因此輸出2.
1.可能引起死迴圈的解法:
一個基本思路:先判斷整數二進位制表示中最右邊一位是不是1。接著把輸入的整數右移一位,此時原來處於從右邊數起的第二位被移到最右邊了,再判斷是不是1。這樣每次移動1位,直到整個整數變成0為止。判斷最右邊是不是1,只要把整數和1做位與運算看結果是不是0就直到了。1除了最右邊一位之外所有位都是0.如果一個整數與1做與運算的結果是1,表示該整數最右邊一位是1,否則是0. 程式碼如下:

     public static int numberOfOne1(int
num){ int count = 0; int rs=0; while(num!=0){ if((rs =num & 1)!=0) count++; num = num >> 1; } return count; }

但是當輸入一個負數時,移位後,最高位仍然為1,如果一直做右移運算,這個數字會變成0xffffffff, 進入死迴圈。
2.常規解法
為了避免死迴圈,我們可以不右移輸入的數字n. 首先把n和1做與運算,判斷n的最低位是不是1.接著把1左移一位得到2,再和n做與運算,判斷n的次低位是不是1…這樣反覆左移,每次都能判斷n的其中一位是不是1.基於這種思路,程式碼如下:

    public static int numberOfOne2(int num){
        int count1 = 0;
        int flag = 1;
        int rs = 0;
        int count2 = 0;
        while(count2<Integer.SIZE){
            if((rs=num&flag)!=0)
                count1++;
            flag = flag << 1;
            count2++;
        }
        return
count1; }

迴圈次數等於整數二進位制的位數。
3.驚喜解法
思路: 如果把一個整數減去1,再和 原整數做與運算,會把該整數最右邊一個1變成0.如二進位制1100,減去1後變為1011,1100和1011做位與運算是1000.把1100最右邊的1變成了0
那麼一個整數的二進位制表示中有多少個1,就可以進行多少次這樣的操作。程式碼如下:

        public static int numberOfOne3(int num){
        int count = 0;
        while(num!=0){
            num = (num-1) & num;
            count++;
        }
        return count;
    }
  判斷一個整數是不是2的整數次方。一個整數如果是2的整數次方,那麼它的二進位制表示中有且只有一位是1,
 而其他所有位是0.把這個整數減去1之後再和它自己做與運算,這個整數中唯一的1就會變成0.

public static boolean is2pow(int num){
    return (num & (num-1))==0;
}

 輸入兩個整數m和n,計算需要改變m的二進位制表示中的多少位才能得到n.比如10的二進位制表示為1010,13的
 二進位制表示為1101,需要改變1010中的3位才能得到1101. 分兩步解決:第一步求這兩個數的異或,第二步統計
 異或結果中1的個數

public static int diff(int num1, int num2){
    int num = num1 ^ num2;
    int count = numberOfOne3(num);
    return count;
}

把一個整數減去1之後再和原來的整數做位與運算,得到的結果相當於是把整數的二進位制表示中的最右邊一個1變成0.很多二進位制的為題都可以用這個

思路解決