《剑指offer》python实现系列,全目录
首先介绍位运算:左移相当于乘以2,右移相当于除以2.
n<
100001010<<2=00101000
n>>m,n是正数时,把n右移m位,最右边的m位被丢弃,最左边补n个0。
n是负数时,把n右移m位,最右边的m位被丢弃,最左边补n个1.
最初想法:
将数字转为二进制数字,然后统计1的个数。
如何计算二进制?
直接调用python函数,bin(7) = 0b111
1
2
3
4
5
6
7
8
9
10
11
12除2求余,逆序排序
用十进制数除以2,可以得到一个商和余数;将余数保存起来,用商再去除以二,再得到一个商和余数.
反复进行,直到商小于1时结束;然后将之前所得的余数逆序输出,得到的就是该十进制数的二进制
def BinaryEncode(n):
#将n转为二进制,n>0
binarylist=[]
while(n>0):
binarylist.append(n%2)#除2求余
n = n//2
print(binarylist[::-1])#逆序输出
BinaryEncode(11)
在计算负数的二进制表示时,先转为原码,再反码,最后补玛。
Eg:-9的二进制表示是11110111
9的原码是00001001,反码是11110110,补玛是11110111.(最后一位加1)
书上思路:
当n大于0时,将n与1做与运算(如果最右边数字是1与1与运算结果为1)
1
2
3
4
5
6
7
8def NumberOf1(self, n):
mycount = 0
if n > 0:
while n:
if n & 1:#与1做与运算
mycount+=1
n = n>>1 #n右移1位,再进行与运算
return mycount
这个只能解决n大于0的情况,因为n为负数右移m位时,要在最左边补m个1,导致无限循环。
另一种思路:
为避免死循环,不右移数字n,先把n和1与运算,判断最低位是不是1。接着把1左移一位得到2,再和n与运算,判断次低位是不是1…反复将1左移,判断n的其中一位是不是1
1
2
3
4
5
6
7
8
9def NumberOf1(self, n):
mycount = 0
flag = 1
while flag:# 改成 for _ in range(32):
if n&flag:
mycount+=1
flag = flag<<1
return mycount
在 C/C++ 实现时,负整数溢出后为最大整数,但 Python 数值类型(Numeric Type)不会出现溢出的情况,所以,此时,还需要对边界值进行限定。
第三种思路:
有个规律:整数n减去1后,再和原整数n与运算,会将n最右边的1变成0,那么n的二进制表示有多少个1就可以进行多少次操作。
比如1100,减去1为1011,1100与运算1011得到1000,即1100最右边的1变成了0。
1
2
3
4
5
6
7
8def NumberOf1(self, n):
mycount = 0
if n<0:
n = n&0xffffffff
while n:
n = n&(n-1)
mycount+=1
return mycount
1python要使用n & 0xffffffff得到一个负数的补码??这个不太清楚,反正是python的一种机制
第四种方法:
1
2
3
4
5def NumberOf1(self, n):
cnt = 0
if n < 0:
n = n & 0xffffffff
return bin(n).count('1')