天天看點

劍指Offer__11、二進制中1的個數

題目描述

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

思路:

先來看一下wangdongli_1993部落格中總結的原碼、反碼、補碼的知識:

數字在計算機中都是二進制來存在,以位元組為機關,一個位元組是8位,這個題目是int類型就是32位

原碼:最高位是符号位,剩下的表示機器數的值

+1:0000 0001

-1:1000 0001

反碼:對于整數,反碼同原碼,對于負數符号位不變,剩下的位取反

+1:0000 0001

-1:1111 1110

補碼:對于整數,補碼同源,對于負數反碼的基礎加1

+1:0000 0001

-1:1111 1111

之後看到了Cytues部落格的分析覺得說的很明白,我在這裡再啰嗦一番:

當n不為0的時候,n的二進制至少有一位是1。

第一種方法比較簡單暴力,因為輸入是整數,int型整數是32位,是以利用for循環,用n和1進行按位與操作(低位依次相與),然後将n右移,進行32次這樣的操作之後就能得到n中1的個數。

第二種方法相比第一種更有技巧一些,我們先來看正數的情況,由預備知識可知,正數的最高位為0,且原碼、反碼、補碼相同,有一個技巧是先将n減一操作,這個時候n的二進制表示從右向左數的第一個1将變成0,而其右側的所有0将變成1,其左側所有數不變。舉個例子,比如整數12,二進制為1100,在減一之後變成1011,可以看到,12在減1之後,其右側第一個1變成0,且1右邊所有0變成1,1左側所有數不變。我們将1100與1011進行與操作,可以發現變成1000,這個時候12的二進制表示最右側1消失了,這個方法的關鍵就在于此,對整數進行多次減1相與的操作,會将整數二進制中1逐漸消除,最終變為0,是以我們的結論是,一個正數,能進行多少次這樣的與操作,其二進制表示就會有多少個1。

我們再來看一下負數的情況,負數以補碼的形式存儲在計算機中,其最高位為符号位,始終為1,是以對負數進行上述操作的時候會出現一個問題,往右移,符号位不變,符号位1往右移,最終可能會出現全1的情況,導緻死循環。與0xffffffff相與,就可以消除負數的影響。

Solution:

Python
(1)
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        count = 0
        for i in range(32):
            if n&1 ==1:
                count += 1
            n = n>>1
        return count

(2)
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        if n < 0:
            n = n&0xffffffff
        count = 0
        while n:
            n = n&(n-1)
            count += 1
        return count
           

Reference:

wangdongli_1993: https://blog.csdn.net/wangdongli_1993/article/details/81123424

Cytues:https://blog.csdn.net/qq_41805514/article/details/82709154