光棍們對1老是那麼敏感,所以每一年的11.11被戲稱爲光棍節。小Py光棍幾十載,光棍自有光棍的快樂。讓咱們勇敢地面對光棍的身份吧,如今就證實本身:給你一個整數a,數出a在二進制表示下1的個數,並輸出。html
例如:a=7python
則輸出:3算法
看到這個題目,咱們大多想到的是「左移」或者「右移」、「與」操做等,而後根據本身的想法很快寫出函數,並輸入7,10等整數驗證,可是這個題目中,咱們須要注意,一個整數的範圍是多少,有多少位,是正整數仍是負整數,在Python中,咱們要知道,Python中彷佛沒有數據位數的概念,數據位數與虛擬內存有關,在咱們認爲溢出以後,python會自動將int類型轉換爲long類型。bash
咱們首先想到的通常都是右移,一直移動到數字爲0便可,以下代碼所示:函數
# -*- coding: utf-8 -*-
# @Time :2018/11/23 21:48
# @Author :AstroBoy
# @Site :
# @File :CalcBinaryNum_1.py
# @Software :PyCharm
def CalcBinaryNum(num):
cnt = 0;
while(num):
if (num & 1):
cnt += 1
num = num >> 1
return cnt
複製代碼
咱們輸入一個負數,發現系統好久沒有輸出結果,這是由於程序已經陷入了死循環,這是由於,在計算機程序語言中,負數在計算機中是用補碼錶示的,負數的補碼最高位爲1,向右移動時,最高位一直用1來填充,因此while循環條件一直爲真。既然右移的方法不可取,那麼咱們就利用左移,在用32位表示的整數中,左移32位1就會變成0,這能夠做爲判斷條件,可是在python中左移並不會簡單的溢出,而是自動擴展位數。爲了在python中使用c語言,能夠利用python的庫庫ctypes,代碼以下:ui
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Time :2018/11/26 21:27
# @Author :AstroBoy
# @Site :
# @File :CalcBinaryNum_Ctype.py
# @Software :PyCharm
from ctypes import *
def CalcBinaryNumByCtype(num):
count = 0
flag = 1
while(c_int(flag).value):
if (c_int(flag & num).value):
count += 1
flag = flag << 1
return count
print(CalcBinaryNumByCtype(5))
print(CalcBinaryNumByCtype(-1))
複製代碼
上述代碼須要循環移位32次才能獲得結果,咱們能夠利用N & (N -1)的方法,把整數的二進制中最右邊的二進制從1變爲0spa
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Time :2018/11/28 20:18
# @Author :AstroBoy
# @Site :
# @File :CalcBinaryNumByCtype_2.py
# @Software :PyCharm
from ctypes import *
def CalcBinaryNumByCtype(num):
cnt = 0;
while(c_int(num).value):
cnt += 1
num = num & (num -1)
return cnt
print(CalcBinaryNumByCtype(5))
print(CalcBinaryNumByCtype(-1))
複製代碼
當前咱們能夠藉助Python特有的庫函數bin,來解決該問題code
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Time :2018/11/28 20:25
# @Author :AstroBoy
# @Site :
# @File :CalcBinaryNumByBin_1.py
# @Software :PyCharm
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Time :2018/11/28 20:18
# @Author :AstroBoy
# @Site :
# @File :CalcBinaryNumByCtype_2.py
# @Software :PyCharm
def CalcBinaryNumByBin(num):
if (num >= 0):
nbin = bin(num)
return nbin.count('1')
else:
num = abs(num)
nbin = bin(num - 1)
return 32 - nbin.count('1')
print(CalcBinaryNumByBin(5))
print(CalcBinaryNumByBin(-1))
複製代碼
當前還有更簡單的作法,利用python的特性:htm
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Time :2018/11/28 20:46
# @Author :AstroBoy
# @Site :
# @File :CalcBinaryNumByBin_2.py
# @Software :PyCharm
def CalcBinaryNumByBin(num):
nbin = bin(num & 0xffffffff)
return nbin.count('1')
print(CalcBinaryNumByBin(5))
print(CalcBinaryNumByBin(-1))
複製代碼
在python中,負數與0xFFFFFFFF按位與,實際上按照語法,負數在作與操做以前會先把本身轉爲計算機中的二進制表示形式,而後與0xFFFFFFFF作與操做,也就變成了一個二進制表示的無符號數blog
除以上方法外,還有查表的方法,先創建一個存儲0到15的二進制中1的個數的列表,而後計算的時候每4位進行一次查表。
#!/usr/bin/python
# -*- coding: utf-8 -*-
# @Time :2018/11/28 21:04
# @Author :AstroBoy
# @Site :
# @File :CalcBinaryNumByList.py
# @Software :PyCharm
counts = [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]
def CalcBinaryNumByList(num):
result = 0
for i in range(0,32,4):
result += counts[(num >> i) & 0xf]
return result
print(CalcBinaryNumByList(5))
print(CalcBinaryNumByList(-1))
複製代碼
當前還有其餘優秀的算法好比平行算法、若是利用C或者C++語言還有位域的方法,再也不一一列舉。
Reference: