【Leetcode】Numbers of 1 bits

本文参考了:

http://blog.csdn.net/canglingye/article/details/44177479


我刚一看,这不挺简单的吗?不断移位,看最低位是不是1,是1就记录一下,很简单嘛,而且移位又那么快。

class Solution:
    def hammingWeight(self, n):
        hw = 0
        while n != 0:
            if n & 1:
                hw += 1
            n >>= 1
        return hw

然后提交就过了。上网一看。自己写的代码简直像是用脚写的……还if个毛啊。直接hw += (n & 1)就得了。

但这都不是重点。我又用JavaScript写了一次。跪了。(切不可乱装逼,但装逼的好处就是挫败以后能长知识)

var hammingWeight = function(n) {
    var hw = 0;
    while(n != 0){
        if (n & 1) {
            hw ++;
        }
        n >>= 1;
    }
    return hw;
};

错误:

Input: 2147483648 (10000000000000000000000000000000)
Output: 0
Expected: 1

Python因为不太在意变量类型,反正一大了就变长整型,所以没什么问题。C++、Java等应该也没问题,只要你指定参数是unsigned int。问题就出现在这个表面上不区分类型(一律都是var)实际会出问题的js。参考以下文章:

http://www.jb51.net/article/44242.htm

在 JavaScript 中,所有整数字变量默认都是有符号整数。JavaScript 进行位操作时,也是采用32位有符号整型,这意味着其转换的结果也是32位有符号整型。

有些时候,我们进行移位会出现意想不到的结果,以下是C语言 与 JS 的对比。

C语言
unsigned int a = 3774191835u;
unsigned int b = a >> 2;
/* b == 943547958 */

-------------------------------

JavaScript
var a = 3774191835;
var b = a >> 2;
/* b == -130193866 */


所以像我刚才那样的写法,移位最后会陷入死循环:10000000000000000000000000000000→11000000000000000000000000000000→11100000000000000000000000000000→……→11111111111111111111111111111111,到最后-1右移一位还是-1,死循环。

(如果把n!=0换成n>0也不行,负数直接退出循环。下文还会说。)

解决方案呢:参考
无符号移位符:>>>
例如:(以下在Nodejs中运行)
>-1 >>> 1  
2147483647 (2 ^ 32 - 1)
>a = -1 >>> 0
4294967295 (相当于由int转成unsigned int了)
>a << 0
-1 (相当于由unsigned int 转成int了)

到此为止,我们似乎已经解决了问题。但其实,还有一种更有效率的算法,它同时也能巧妙规避上述的移位错误。
var hammingWeight = function(n) {
    var hw = 0;
    while(n){
        n &= (n - 1);
        hw ++;
    }
    return hw;
};
每进行一次n &= (n-1),就把原n的最后一个1去掉,这样循环进行了几次,就说明有多少位的1。这里要注意,while循环条件(相当于n!=0)不能替换成n > 0,原因和刚才说的一样,大于2147483647的数在进行过位运算以后会被理解为负数,这样就不满足循环条件。
比如:
Input: 4294967295 (11111111111111111111111111111111)
Output: 1
Expected: 32
进入了循环,位运算后,n被赋值:11111111111111111111111111111110,我们期望的是4294967294,但实际解读为-2,hw++,退出循环。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值