請實現一個函數,輸入一個整數,輸出該數二進制表示中 1 的個數。例如,把 9 表示成二進制是 1001,有 2 位是 1。所以,若是輸入 9,則該函數輸出 2。編程
測試用例1:ide
測試用例2:函數
測試用例3:測試
首先來分析題目,要統計二進制中1的個數,那麼咱們首先想到的是 要將此數的每一個比特位都要遍歷一遍,而後判斷爲1count++,最後返回count。就寫出以下代碼優化
int hammingWeight(uint32_t n) { int count = 0; while(n) { if(n&1) count++; //此處移位時,若是n爲負數可能會致使死循環 n >>= 1; } return count; }
上面的代碼在統計無符號數時,結果是正確的,可是,在算負數時,可能會致使死循環。
此處咱們採用的 位運算 來代替 除法運算,由於計算機中除法的效率要比比移位運算要低得多。咱們在實際編程中要儘可能地用移位運算符代替乘除法。
再者咱們來討論一下測試用例爲負數。右移運算符的特色是,右移n位的時候,最右邊的n位將被丟棄。在右移處理最左邊位的情形比較複雜。若是數字是一個無符號值,則用0填補最左邊的n位;若是數字爲有符號數,則用數字的符號位填補最左邊的n位。也就是說,若是數字原先是正數,則右移以後在最左邊補n個0;若是數字原先是負數,則右移以後在最左邊補n個1。 因此負數在進行移位時,最終因爲最高位一直補1致使最終結果陷入死循環。故設計出上述代碼是由問題的,咱們能夠對其進行調整。ui
int hammingWeight(uint32_t n) { int count = 0; unsigned int flag = 1; while(flag) { if(n&flag) count++; flag = flag << 1; } return count; }
爲了不死循環,此處咱們不右移輸入的數字n,而是把n和1 按位與 ,判斷i的最低位是否是爲1,接着把i左移1位,再和n作按位與運算。這樣反覆右移就能計算出n中二進制位1的個數。這種解法唯一的不足之處是不管n中二進制位有多少個1,都要進行32次循環。那麼還能不能在優化一下呢,答案是確定能夠,來看一下最終比較完美的解答:
完美解答:設計
int hammingWeight(uint32_t n) { int count = 0; while(n) { ++count; n = (n-1)&n; } return count; }
此處將位運算的靈活性體現到了機制,能夠看出代碼設計的很是巧妙精簡。其精髓就在於此句 n = (n-1)&n
。你們能夠本身體會一下此處的妙筆。3d