天天看點

劍指offer11--二進制1的個數題目描述思路實作技巧知識點

題目描述

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

思路

首先可以利用原碼反碼補碼的知識直接暴力求解。

源碼:首位為符号位,正0負1,後面為真值(絕對值)

反碼:正數等于原碼,負數除了符号位其餘取反

補碼:正數等于原碼,負數為反碼+1

當輸入為正數時,直接除2取餘法;

當輸入為負數時,根據補碼和源碼的關系來轉化成正數。

例如:對于一個8位數,符号位占1位,

補碼 1000 0001 -1 1000 1001 -9
反碼 1000 0000 1000 1000
原碼 1111 1111 -127 1111 0111 -119

補碼與原碼絕對值相加得到128,即2^7。是以輸入一個負數,用128相加得到一個正數,例如-119+128=9,1共有2個,再加上符号位一共是3位。

同理,對于一個32位數,除去符号位,還有31個有效位數,即用2^31去與負數相加。

實作

class Solution {
public:
     int  NumberOf1(int n) {
         if (n==0) return 0;
         int ret=0;
         if (n>0)
         {
             int m=0;
             while (n!=0)
             {
                 m=n%2;
                 n/=2;
                 if (m!=0) ret++;
             }
         }
         else
         {
             ret=NumberOf1(2147483648+n)+1;//2^31相加,最後結果+1(符号位)
         }
         return ret;
     }
};
           

技巧

對于一個不為0的2進制數,肯定存在若幹個1;當對其減1的時候,最右邊的1變成0,這個1右邊的0全變成1,相當于消掉了原來位置上的1,但是又引入了更多的1,那麼如何解決這個引入的問題?隻需要跟原來的數做與運算,例如:

1100-1=

1011 再與

1000 這樣就消去了最右邊的1

如此循環減1下去,直到為0

循環次數即等于1的個數

實作:

class Solution {
public:
     int  NumberOf1(int n) {
         if (n==0) return 0;
         int ret=0;
         while (n!=0)
         {
             ret++;
             n=n&(n-1);
         }
         return ret;
     }
           

知識點

原碼反碼補碼

繼續閱讀