首页 > 编程知识 正文

剑指offer,剑指offer答案python

时间:2023-05-05 09:30:01 阅读:36660 作者:3136

阅读目录主题说明思路和Python的实现

主题说明

输入整数,输出该数的二进制表示中的1的个数。 其中负数用补数表示。

思路和Python实现首先解决:负数用补数表示?

在二进制码中,为了区分正负数,以最高位比特为已编码比特的方式进行区分,正数的已编码比特为0,负数的已编码比特为1。 剩下的就是这个数量的绝对值部分,绝对值部分可以用原码、反码、补码三种形式来表示。

源代码是最简单的,最好理解。 原代码是绝对值的二进制格式。 例如,7的8位二进制原码是0000111,-7的8位二进制原码是10000111。

但是,二进制运算中,源代码的运算是不够的。 如果两个数相加,首先判断这两个数的符号是否相同,如果符号不同,则判断哪一个数的绝对值大。 所以在计算机上,通常都是采用 补码 形式

正整数的补码与原码形式相同,例如7的8位二进制代码为00000111; 负整数补数可以在将这个负整数的绝对值求反码再加1,连同符号位1一起表示就可以了中获得。 例如,-7的8位二进制补码:反求“-7”的绝对值7为1111001,与符号位1一起为11111001。

实际操作:

-2怎么表示?

首先,绝对值为2的二进制代码为0 000…0010反码为1 111…1101,再加1

得到- 2的补数后,1 111…1110

以-14为例

首先取绝对值的原码: 14即000000000000000000000000000000000000000000000000000000000000110

反码: 1111111111111111111111111111111111111111111111110001

补数: 1111111111111111111111111111111111111111111111111110010

所以-14的二进制数是111111111111111111111111111111111111111111111111111111111111110010

得到二进制文件所需的整数是多少? 那就是反过来取相反数

例如,二进制是11111111111111111111111111111111111111111111110010

得到负号1后111111111111111111111111111111111111111111111111111111111111111111110001

原码: 0000000000000000000000000000000000000000000000000110

也就是说,1110=14,所以取反的话就是-14

表达式包括允许计算机以任意整数n0xffffffffffff显示任意数量的方法!

让我们来推测一下其原理。 int是有符号类型,有符号类型最高为符号位。 此外,0xFFFFFFFF (即4字节32位)都是1,符号位是1,因此该数为负。 f是二进制的15,4位都是1111,也就是n是正整数时,是32位的1还是本身

如果n是负数,则二进制表示为补码,并能确定该编码比特必须是1; 其绝对值的反符号1 (补码) 32位的1可以等待负数的表示方式; 上面的-2先找到那个补码。 1 111…1110 1111…1111可以得到1 111…1110。

等等,我晕了。 这个。 而且,查找资料发现,Python能表达的整数比C/C大得多。 实际上,只要有足够的存储区域就可以表示Python,但不像C/C那样只有一个CPU字大小,在Python内部好像用正数表示整数,表示负数的时候只是前面加负号。 如下

Python没有unsigned int类型,负数0xFFFFFFFF返回的数为正数

Python使用n0xffffffff得到一个数的补数

想法1 :位运算

判断是否为负数,对负数进行n0xFFFF FFFF处理,可以开始判断和统计二进制中的第一个数; 接下来是位运算的巧妙运用。 利用n1和n1这两个位运算。 因为除了最低有效位是1之外,所有剩馀位都是0,所以n-1不是0就可以确定n的当前最低有效位是1,从而n-1可以检测当前最低有效位是否是1。 的各位继续判断,n向右移动一位,在判断结束之前舍弃当前位。 即,n是0位运算(1) 左移运算符

将运算对象的各二进制位全部向左移动几个。符号位不变,低位(右边)补 0

11 2=44 #详细的过程000000000000000000000000000000000000000000100 (最高位为0,因此表示正数) (443333 )

11111111 11111111 11111111 11110010 (-14的补码)<< 211111111 11111111 11111111 11001000 (补码)# 看上面的结果,符号位为1是负数,我们还要将它转换成 原码 才能计算出它的值11111111 11111111 11111111 11001000 (补码)11111111 11111111 11111111 11000111 (反码)10000000 00000000 00000000 00111000 (原码)# 所以最后结果为:-56

左移,对于正数来说,左移多少位等于 乘以 2 ^ (左移位数);左移1 相当于乘以2(但效率比乘法高)

(2)>> 右移运算符
将运算对象的 各二进制位 全部 右移若干位:低位溢出,符号位不变,并用符号位补溢出的高位

4 >> 2 = 1 # 详细过程00000000 00000000 00000000 00000100 >> 2 00000000 00000000 00000000 00000001(因为最高位是0,它表示一个正数)# 所以最后结果为:1————————————-14 >> 2 = -4 # 详细过程11111111 11111111 11111111 11110010 (-14的补码)>> 2 11111111 11111111 11111111 11111100 (补码)# 看上面的结果,符号位为1是负数,我们还要将它转换成 原码 才能计算出它的值11111111 11111111 11111111 11111100 (补码)11111111 11111111 11111111 11111011 (反码)10000000 00000000 00000000 00000100 (原码)# 所以最后结果为:-4

右移,对于正数来说,右移多少位等于 除以 2 ^ (右移位数);右移 1 相当于除以2(效率比除法高哦)

# 左移class Solution: def NumberOf1(self, n): if n<0: n = n & 0xFFFFFFFF count=0 for i in range(32): mask = 1 << i if n & mask : # 注意这里不能写 成 if n & mask == 1 : count+=1 return count # 右移class Solution: def NumberOf1(self, n): # write code here if n<0: n = n & 0xFFFFFFFF count = 0 while n: if n & 1 : # 或者写 if n & 1 ==1: 也行 count += 1 n = n >> 1 # 不断的重复右移一位 return count

判断次数更少,更快,更优的位运算解决方法

如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。

例如:一个二进制数1010,从右边数起第二位是处于最右边的一个1。减去1后,第二位变成0,它后面的一位0变成了1,而前面的1保持不变,因此得到的结果是1001。即,n减1的结果是把最右边的一个1开始的所有位都取反。

这个时候如果我们再将 原来的整数 和 减去1之后的整数结果 做 &运算,从原来整数最右边一个1那一位开始所有位都会变成0,其他位保持不变。如1010&1001=1000。

也就是说,把一个整数n 减去1,再和原整数做与运算,会把该整数最右边一个1变成0,不断做 & 运算,直到 n 最后一次做 & 运算变成 0 ;那么可以进行多少次这样的操作,一个整数的二进制就有多少个1

让 n & (n-1) 具体过程如下图:

class Solution: def NumberOf1(self, n): if n < 0: n = n & 0xFFFFFFFFcount = 0 while n: count += 1 # 只要n不为0 就要记录一次,所以要写在前面,开始能进来就不为0 n = n & (n-1) return count

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。