11.二進制中1的個數【位運算】

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

       本題考查的是位運算,先大概回憶下位運算的基本概念。

       1.算術左移和邏輯左移

       算術左移和邏輯左移一樣都是右邊補0:

       比如 00101011

       算術左移一位:01010110

       邏輯左移一位:01010110

       對於二進制的數值來說左移n位等於原來的數值乘以2的n次方

       比如00011010十進制是26,左移兩位後是01101000轉成十進制是104恰好是26的4倍。

       ps:這種倍數關係只適用於左移後被捨棄的高位不含1的情況,否則會溢出。

       2.算術右移和邏輯右移

       邏輯右移很簡單,只要將二進制數整體右移,左邊補0即可:

       如10101101邏輯右移一位爲01010110

       算術右移符號位要一起移動,並且在左邊補上符號位,也就是如果符號位是1就補1符號位是0就補0

       比如:11100算術右移一位爲11110(符號位1跟着一起移動並且左邊補了1)

       對於二進制的數值來說右移n位等於原來的數值除以2的n次方

       比如10110100十進制是76(需要先將這個補碼轉換成原碼之後再轉換成十進制),右移兩位後是11101101轉成十進制是19恰好是76的4倍。

       ps:這種倍數關係只適用於右移後被捨棄的低位不含1的情況,否則每舍一次1則代表餘數被捨去,保留整數部分。

       3.C++中的位運算

       左移都是右邊補0,所以主要說下右移中算數右移和邏輯右移的區別。

       C/C++語言中邏輯右移和算數右移共享同一個運算符>>。編譯器決定使用邏輯右移還是算數右移,根據的是運算數的類型。如果運算數類型是unsigned則採用邏輯右移,而signed則採用算數右移。

       在本題中,需要讓負數使用邏輯右移操作,由於C/C++ 語言中邏輯右移和算數右移共享同一個運算符>>,因此此處使用運算符>>對負數進行移位得到的是算術右移,最高位一直補1,會進入死循環。因此使用C++ 進行本題的解答需要一點小小的處理,如果是Java等可以直接使用>>>進行邏輯右移,無C++語言特性的影響。

       思路:首先判斷n是不是負數,當n爲負數的時候,直接用後面的while循環會導致死循環,因爲負數向右移位的話最高位補1 。因此需要一點點特殊操作,可以將最高位的符號位1變成0,也就是n & 0x7FFFFFFF,這樣就把負數轉化成正數了,唯一差別就是最高位由1變成0,因爲少了一個1,所以count加1,之後再按照while循環裏處理正數的方法來操作就可以了。

       C++代碼如下:

class Solution{
public:
    int NumberOf1(int n){
        int num = 0;
        if (n < 0){
            n = n & 0x7FFFFFFF;
            ++num;
        }
        while (n != 0){
            if (n & 1 == 1){
                num++;
            }
            n = n >> 1;
        }
        return num;
    }
};

       位運算概念部分參考博客:https://blog.csdn.net/yddj5/article/details/52822366

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