剑指offer:二进制中1的个数(Python)

题目描述

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

解题思路

思路1

首先,这种基础的求二进制中1的个数的问题,对于强大的Python,一定存在一些好用的库函数。果不其然,代码如下:

Python代码1
def NumberOf1(self, n):
    if n >= 0:
        return bin(n).count('1')
    else:
        return bin(n & 0xffffffff).count('1')

或者

def NumberOf1(self, n):
    return bin(n & 0xffffffff).count('1')
思路2

思路1虽然简单,但太没意思了。这基本上就直接无视了解题的乐趣,想必也不是出题人的本意。如何在不用Python自带的库函数的情况下灵巧求解呢?
可以将n上的每一位与1取与,统计1的个数;在求解的过程中每次循环时1左移一位,即n<<1 。但有更漂亮的解法:

  1. 如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
  2. 把原来的整数和减去1之后的结果做与运算,从原来整数最右边一个1那一位开始所有位都会变成0。—-牛客网

举例来说,6的二进制是 110 ,6-1=5的二进制是 101,6&5=100, 如此操作之后6中原来的110变为100,循环计数统计1的个数,直至n变为0为止。

Python代码(Wrong)
def NumberOf1(self, n):
    count = 0
    while n != 0:
        count += 1
        n = n & (n-1)
    return count

但是!上述代码在n小于0时会无限循环!(Python3.6.1中)
打印n 和 n的二进制表示的值,发现了一个很奇怪的现象。以n=-10举例:
初始时n的二进制值为:

‘0b11111111111111111111111111110110’

循环计数29次后,n的10进制值为:-2147483648,n的二进制值为:

‘0b10000000000000000000000000000000’

循环计数30次后,n的10进制值为:-4294967296,n的二进制值为:

‘0b0’

也就是说,此时虽然n的二进制值为0b0,但是内存中显示n的十进制值为-4294967296,满足 n!=0 的条件, 循环会继续执行。在此之后的循环中,n的二进制表示一直显示为0b0, 但内存中n的十进制数继续不断减少。。。
为什么呢?
我在获取上述n的二进制值时,用的语句是:

print(bin(n & 0xffffffff ))

而直接调用bin语句,会发现:

bin(-10)
'-0b1010'
bin(-12)
'-0b1100'
bin(-16)
'-0b10000'
... ...
bin(-2147483648)
'-0b10000000000000000000000000000000'
bin(-4294967296)
'-0b100000000000000000000000000000000'
bin(-8589934592)
'-0b1000000000000000000000000000000000'
bin(-17179869184)
'-0b10000000000000000000000000000000000'

即在当前情况下,继续循环时n的二进制不断补0,使得n继续不断减小。。。也就是说Python3.6.1中int类型不止32位。。。

问了度娘之后才知道,原来Python2的int类型有32位和64位一说,但到了Python3,当长度超过32位或64位之后,Python3会自动将其转为长整型,长整型理论上没有长度限制。

Python代码(Rignt)
def NumberOf1(self, n):
    count = 0
    while n&0xffffffff != 0:
        count += 1
        n = n & (n-1)
    return count
  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值