題目:
輸入乙個整數,輸出該數二進位制表示中1的個數。其中負數用補碼表示。
解法一:
class
solution
:def
numberof1
(self, n)
:# write code here
sum=
0while n !=0:
if n &1==
1:sum+=
1 n = n >>
1return
sum
上面的**對於正數沒有任何問題,但是對於負數就會出現死迴圈,因為-1右移仍然是-1,而不會變成0,所以迴圈不會終止。有關-1右移一位還是-1的內容請參考:負數的二進位制表示與位運算
解法二:
既然上面的解法存在問題,我們就得使用另一種解法。這種解法是劍指offer上給出的解法。利用二進位制減法的性質,如果乙個二進位制數的最後一位是1,則減去1後最後一位變成0,其他位不變。如果最後一位不為0,則減去1後最右邊的1變成0,右邊的0變成1,前面的位不變。所以n&(n-1)可以消掉最右邊的一位1。迴圈使用這種方法,每次可以消掉乙個1,直到n變成0。
當年我很年輕,不知人生苦短,所以我用c++,下面是c++通過的**:
class solution
return count;}}
;
使用c++上面的**沒有任何問題,可以順利通過測試。
但是,當我不再年輕,認識到人生苦短之後,我開始使用python,於是我又寫了乙份python**,然而問題來了:
class
solution
:def
numberof1
(self, n)
:# write code here
# n&n-1可以消去最後乙個0
count =
0while n !=0:
count +=
1 n = n &
(n-1
)return count
class
solution
:def
numberof1
(self, n)
:# write code here
# n&n-1可以消去最後乙個0
sum=
0if n <0:
n = n &
0xffffffff
while n !=0:
sum+=
1 n = n &
(n-1
)return
sum
但是對於其中的n = n & 0xffffffff
我十分疑惑。n與上 0xffffffff還是它本身,為什麼還要與呢?重要的是這樣的**真的能夠解決超時的問題。欲知後事如何我們請往下看。。。
python中的二進位制
print
(bin(5
))print
(bin(-
5))
可以看到5和-5的二進位制表示分別為:
0b101
-0b101
我們知道python沒有位數的限制,python可以表示無限長的整數,所以其實在python中5的二進位制補碼表示其實這樣的:
0000000...101 #前面有無限個0,第一位可以理解為符號位
-5的二進位制補碼表示其實這樣的:
11111111...011 #前面有無限個1,第一位可以理解為符號位
所以在python中,任何負數的二進位制表示都有無限個1。每次n&(n-1)消去最右邊乙個1,但是永遠消不完。
用了python好像苦短的人生更短了。。。
但是為什麼n & 0xffffffff就可以解決這個問題呢:
0xffffffff相當於32位個1,這樣n & 0xffffffff就取出了-5的補碼表示的後32位,-5補碼表示就變成了:
00000....111111.....011 #無限個0,29個1,第一位可以理解為符號位
由於第一位符號位變了,這樣-5的補碼11111111…011就變成了00000....111111.....011
就變成了,這樣1的數目就是有限的了。由於前面是0,可以看出這是乙個正數的補碼,通過**我們可以驗證這個數是4294967291。這個正數4294967291的補碼和-5的補碼具有相同數目的1。所以這是乙個我們統計這個正數中含有的1就好了。
print(-
5)print(-
5&0xffffffff
)
-5
4294967291
所以這也解釋了當n小於0時,這句**的有效性n = n & 0xffffffff
。
解法三:
其實只要明白了,使用python,開始**不work的原因是因為python對負數補碼的表示有無數個1,問題就容易解決了。發現了問題,問題就解決了一半。還有另一種辦法可以解決這種負數的補碼有無限個1的問題。
```python
class
solution
:def
numberof1
(self, n)
:# write code here
# n&n-1可以消去最後乙個0
count =
0if n <0:
#把符號為變成0,剩下的不變
count +=
1 n = n &
0x7fffffff
while n !=0:
count+=
1 n = n &
(n-1
)return count
其實只要理解了我上面的就是這種方法的道理是一樣的,在此就不做過多的解釋了。
其實這都是python的鍋:人生苦短我用python,我用python人生更苦~
上面的內容都是自己的推測和**驗證,如有問題歡迎批評指正~
劍指Offer 二進位制中1的個數
題目 請實現乙個函式,輸入乙個整數,輸出該數二進位制表示中1的個數。例如把9表示成二進位制是1001,有2位是1。因此如果輸入9,該函式輸出2。1 可能引起死迴圈的解法 先判斷整數二進位制表示中最右邊一位是不是1。接著把輸入的整數右移一位,此時原來處於從右邊數起的第二位被移到最右邊了,再判斷最右邊的...
劍指Offer 二進位制中1的個數
輸入乙個整數,輸出該數二進位制表示中1的個數。其中負數用補碼表示。錯誤解法 public class solution return num 若輸入的數字為負數,因為為補碼表示方式,所以高位一直是1,所以會陷入死迴圈。方法一 從高位開始計算 public class solution return ...
劍指OFFER 二進位制中1的個數
public class solution return count 答案正確 恭喜!您提交的程式通過了所有的測試用例 分析一下 這段小小的 很是巧妙。如果乙個整數不為0,那麼這個整數至少有一位是1。如果我們把這個整數減1,那麼原來處在整數最右邊的1就會變為0,原來在1後面的所有的0都會變成1 如果...