Java篇—二進制中1的個數(思路解析及代碼實現)

題目描述:

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

解法1思路解析:

step 1:num的二進制的最右邊位與1相與,如果不爲0,則count加1;

step 2:否則,對1左移一位,繼續與num的二進制的最右邊數的第二位進行相與;

step 3:依次循環,即可完成。

解法1代碼實現:

import java.util.Scanner;
public class Exercise18 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()){
            int num = sc.nextInt();
            int count = NumberOf1(num);
            System.out.println(count);
        }
    }

    private static int NumberOf1(int num) {
        //判斷num是否爲0
        if(num == 0){
            return 0;
        }
        //記錄1的出現次數
        int count = 0;
        int flag = 1;
        //flag一直向左移,當到1000 0000 0000 0000時,如果再左移,就回到了0
        while(flag != 0){
            //num有可能是負數,當它與flag相與的時候,結果小於0,
            //所以只要讓兩者相與的結果不爲0即可
            if((num & flag) != 0){
                count++;
            }
            //flag左移一位
            flag = flag << 1;
        }
        return count;
    }

}

解法1缺陷解析:

循環次數較多,解法1代碼的循環次數跟數據類型有關,如果是int型(4字節),那麼它在計算機中存儲的bit位爲32位,如果是short型(2字節),那麼它在計算機中存儲的bit位爲16位,如果數據沒有佔滿整個bit位的話,即使得到我們想要的結果,flag還是要進行左移,直到flag爲0,換句話講,int型的數據,不管它是多大,flag都要左移32位,即循環了32次,對於short型數據,flag要左移16位,即循環了16次。

 

解法2思路解析:

step 1:num的二進制與1相與,如果不爲0,則count加1;

step 2:否則,對num無符號右移一位,繼續與1進行相與;

step 3:依次循環,即可完成。

解法2代碼實現:

import java.util.Scanner;
public class Exercise18 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()){
            int num = sc.nextInt();
            int count = NumberOf2(num);
            System.out.println(count);
        }
    }

    private static int NumberOf2(int num) {
        //判斷num是否爲0
        if(num == 0){
            return 0;
        }
        //記錄1的出現次數
        int count = 0;
        int flag = 1;
        while(num != 0){
            //num有可能是負數,當它與flag相與的時候,結果小於0,
            //所以只要讓兩者相與的結果不爲0即可
            if((num & flag) != 0){
                count++;
            }
            //num無符號右移一位,如果改成有符號右移,正數沒影響,負數會使系統陷入死循環
            num = num >>> 1;
        }
        return count;
    }

解法2缺陷解析:

(1)對於解法2,如果不注意將代碼寫成有符號右移,即num = num >> 1,拿到的num又恰好是個負數(負數,在進行右移的時候,最高位會進行補位運算,不管右移多少次,始終都會出現這一個1—符號位的1,這個時候就會造成一個負數得到無數個1),那麼將會使系統陷入死循環。

(2)對原數字進行了更改,不利於後期使用。

 

解法3思路解析:

step 1:如果一個整數不爲0,那麼這個整數的二進制至少有一位是1;

step 2:如果我們把這個整數減1,那麼原來處在整數最右邊的1就會變爲0,原來在1後面的所有的0都會變成1(如果最右邊的1後面還有0的話),更改後的1(1變爲0)的前面的其餘位數不受影響;

step 3:num 與 num - 1進行相與,消除該數二進制位最右邊的1;

step 4:依次循環,即可完成。

解法3代碼實現:

import java.util.Scanner;
public class Exercise18 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        while (sc.hasNext()){
            int num = sc.nextInt();
            int count = NumberOf3(num);
            System.out.println(count);
        }
    }

    private static int NumberOf3(int num) {
        //判斷num是否爲0
        if(num == 0){
            return 0;
        }
        //記錄1的出現次數
        int count = 0;
        //當num不爲0時,其它任意整數的二進制至少有一個1,進入循環後,count先加1
        while(num != 0){
            count++;
            /**
             * num-1,如果n的二進制右邊數第一位是1,則變爲0,如果到某幾位才爲1時,
             * 如:0110 0100,則最右邊的1變爲0,
             * 原先1的右邊的00都變爲11 即0110 0011,然後與num相與;
             * 得到的值正好是:0110 0000,(剛好消除了最右邊的那一個1)
             * 最終結論,num & (num - 1)只會將最右邊的1變爲0
             */
            num = num & (num - 1);
        }
        return count;
    }

解法3缺陷解析:

對原數字進行了更改,不利於後期使用。

 

題目總結:

(1)解法1的循環次數較多,但沒有更改原數據;

(2)解法2更改了原數據,如果代碼寫成有符號右移,對於負數,會造成系統的死循環;

(3)解法3更改了原數據。

 

計算機中數的存儲形式:

https://blog.csdn.net/weixin_43761659/article/details/98472451

Java移位運算符:

https://blog.csdn.net/weixin_43761659/article/details/98472473

 

心靈雞湯:考慮一千次,不如去做一次;猶豫一萬次,不如實踐一次;華麗的跌倒,勝過無謂的彷徨,將來的你,一定會感謝現在奮鬥的自己。

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