劍指 Offer-求二進(jìn)制中 1 的個(gè)數(shù)(Python 實(shí)現(xiàn)過程遇到的問題)

輸入一個(gè)整數(shù)大渤,輸出該數(shù)二進(jìn)制表示中1的個(gè)數(shù)。其中負(fù)數(shù)用補(bǔ)碼表示祠锣。

思路

  1. 需要一個(gè)循環(huán)結(jié)構(gòu)酷窥,不斷對輸入數(shù)進(jìn)行 無符號(hào) 右移動(dòng)。
  2. 在循環(huán)體的結(jié)構(gòu)當(dāng)中伴网,使用適當(dāng)?shù)倪^濾器(1 這個(gè)整數(shù))對輸入數(shù)進(jìn)行 邏輯與(&)操作:結(jié)構(gòu)為 1 的時(shí)候計(jì)數(shù)(count)增加 1蓬推;否則選擇跳過繼續(xù)執(zhí)行循環(huán) 結(jié)構(gòu)。
  3. 當(dāng) 無符號(hào)右移 操作執(zhí)行到終點(diǎn)時(shí)候(輸入數(shù)變成 0)澡腾,終止循環(huán)沸伏,同時(shí)返回最終計(jì)數(shù)的變量。

位運(yùn)算基礎(chǔ)知識(shí)

計(jì)算機(jī)對有符號(hào)數(shù)(包括浮點(diǎn)數(shù))的表示有三種方法:原碼动分、反碼和補(bǔ)碼(補(bǔ)碼 =反碼 + 1)毅糟。在 二進(jìn)制里,是用 0 和 1 來表示正負(fù)的澜公,最高位為符號(hào)位姆另,最高位為 1 代表負(fù)數(shù),最高位為 0 代表正數(shù)坟乾。以 8 位的 byte 為例迹辐,最大值為:0111,1111,最小值為 1000,0000甚侣。

以此類推右核,在 Integer 的情況下,-5(toBinaryString)的結(jié)果為:1111,1111, 1111,1111,1111,1111,1111,1011渺绒。

右移

打印 -3 >> 1:-2贺喝。這里看一下具體的計(jì)算過程(正數(shù)左補(bǔ) 0,負(fù)數(shù)左補(bǔ) 1):

  1. Integer.toHexString(-3) 得到 3 的 16 進(jìn)制:0xfffffffd(此為-3的補(bǔ)碼,計(jì)算機(jī)中負(fù)數(shù)用補(bǔ)碼表示)宗兼。
  2. 將其轉(zhuǎn)換成2進(jìn)制為1111,1111,1111,1111,1111,1111,1111,1101躏鱼。
  3. 右移一位得到:1111,1111,1111,1111,1111,1111,1111,1110,顯而易見此為-2補(bǔ)碼殷绍。

左移

打印 -3<<1:-6染苛。左移相對來說比較簡單(正負(fù)數(shù)皆右補(bǔ) 0):

  1. -3 的二進(jìn)制為:1111,1111,1111,1111,1111,1111,1111,1101。
  2. 左移一位為:1111,1111,1111,1111,1111,1111,1111,1010,其為-6的補(bǔ)碼茶行。

無符號(hào)右移

打印 -3<<1:2147483646躯概。遵循的原則:正數(shù)左補(bǔ) 0,負(fù)數(shù)左補(bǔ) 1

  1. -3 的二進(jìn)制為:1111,1111,1111,1111,1111,1111,1111,1101畔师。
  2. 無符號(hào)右移娶靡,高位補(bǔ) 0 得到:0111,1111,1111,1111,1111,1111,1111,1110,其為 2147483646 的補(bǔ)碼/原碼(正數(shù)的原碼和補(bǔ)碼相同)看锉。

消失的無符號(hào)左移

為什么沒有無符號(hào)左移姿锭?

因?yàn)樽笠剖窃诤竺嫜a(bǔ) 0,而右移是在前面邊補(bǔ) 1 或 0伯铣,有無符號(hào)是取決于數(shù)的第一位是 0 還是 1呻此,所以右移是會(huì)產(chǎn)生到底補(bǔ)1還是0的問題。而左移始終是在右邊補(bǔ)腔寡,不會(huì)產(chǎn)生符號(hào)問題焚鲜,所以沒有必要無符號(hào)左移 <<<。因此放前,無符號(hào)左移 <<< 和左移 << 是一樣的概念恃泪。

常規(guī)代碼實(shí)現(xiàn)

根據(jù)上述的思路和基本概念,這里用 JS 來對這道題進(jìn)行解答:

function NumberOf1(n) {
    // write code here
    let count = 0
    for(;n != 0; n >>>= 1) {
        if(n & 1) {
            count++
        }
    }
    return count
}

Python 中遇到的問題和解決方法

Python 中沒有無符號(hào)右移

在 JS 中犀斋,可以使用 a >>> b 來實(shí)現(xiàn)無符號(hào)位移贝乎,Python 中沒有這個(gè)運(yùn)算符,只能自己實(shí)現(xiàn)了
無符號(hào)右移 >>>:就是將有符號(hào) int a 和 b 轉(zhuǎn)為無符號(hào) uint 后叽粹,再進(jìn)行普通右移 >> 運(yùn)算览效。比如 -1 的有符號(hào) int 就是 -1,無符號(hào) int 就是 4294967295虫几。

因?yàn)?Python 中沒有 無符號(hào)右移锤灿,因而不能對最高位補(bǔ) 0,對于 負(fù)數(shù) 還是繼續(xù)用 1 補(bǔ)進(jìn)辆脸,這樣就沒有辦法正確的統(tǒng)計(jì) 1 的個(gè)數(shù)但校。

解決方法

解決前:

  • Python:打印 -3 >> 1,輸出 -2(不符合要求)
  • JavaScript:打印 -3 >>> 1啡氢,輸出 2147483646(符合要求)

解決后:

  • Python:打印 (-3 & 0xffffffff) >> 1状囱,輸出 2147483646(符合要求)

原理:負(fù)數(shù)與邊界數(shù)按位與(&) 操作后 得到的是對應(yīng)二進(jìn)制數(shù)的真值:

-3 & 0xffffffff —> 4294967293

此時(shí)再在 Python 當(dāng)中對其進(jìn)行正常右移 >> 操作則是對一正數(shù)進(jìn)行右移,前面補(bǔ) 0倘是,符合要求亭枷;如果沒進(jìn)行這一步操作,右移依然是針對負(fù)數(shù)來進(jìn)行操作的搀崭,前面補(bǔ) 1叨粘,不符合要求。

代碼實(shí)現(xiàn)

有了以上的原理鋪墊,在 Python 的代碼當(dāng)中升敲,在第一次右移操作之前答倡,先對被操作數(shù)進(jìn)行和邊界數(shù) 0xffffffff 的 & 運(yùn)算,可得到正確的執(zhí)行結(jié)果:

class Solution:
    def NumberOf1(self, n):
        # write code here
        count = 0
        n = n & 0xffffffff
        while n != 0:
            if (n & 1) == 1:
                count += 1
            n = n >> 1   
 
        return count

其他的解決辦法

class Solution:
    def NumberOf1(self, n):
        # write code here
        M1 = 0x55555555
        M2 = 0x33333333
        M4 = 0x0f0f0f0f
        M8 = 0x00ff00ff
        M16 = 0x0000ffff
 
        n = (n & M1) + ((n >> 1) & M1)
        n = (n & M2) + ((n >> 2) & M2)
        n = (n & M4) + ((n >> 4) & M4)
        n = (n & M8) + ((n >> 8) & M8)
        n = (n & M16) + ((n >> 16) & M16)
 
        return n
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末驴党,一起剝皮案震驚了整個(gè)濱河市瘪撇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌鼻弧,老刑警劉巖设江,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锦茁,死亡現(xiàn)場離奇詭異攘轩,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)码俩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門度帮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人稿存,你說我怎么就攤上這事笨篷。” “怎么了瓣履?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵率翅,是天一觀的道長。 經(jīng)常有香客問我袖迎,道長冕臭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任燕锥,我火速辦了婚禮辜贵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘归形。我一直安慰自己托慨,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布暇榴。 她就那樣靜靜地躺著厚棵,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蔼紧。 梳的紋絲不亂的頭發(fā)上窟感,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音歉井,去河邊找鬼柿祈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的躏嚎。 我是一名探鬼主播蜜自,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼卢佣!你這毒婦竟也來了重荠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對情侶失蹤虚茶,失蹤者是張志新(化名)和其女友劉穎戈鲁,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嘹叫,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡婆殿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了罩扇。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婆芦。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖喂饥,靈堂內(nèi)的尸體忽然破棺而出消约,到底是詐尸還是另有隱情,我是刑警寧澤员帮,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布或粮,位于F島的核電站,受9級(jí)特大地震影響捞高,放射性物質(zhì)發(fā)生泄漏氯材。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一棠枉、第九天 我趴在偏房一處隱蔽的房頂上張望浓体。 院中可真熱鬧,春花似錦辈讶、人聲如沸命浴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽生闲。三九已至,卻和暖如春月幌,著一層夾襖步出監(jiān)牢的瞬間碍讯,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工扯躺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留捉兴,地道東北人蝎困。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像倍啥,于是被迫代替她去往敵國和親禾乘。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容