【剑指 offer】(十)—— 二进制形式 1 的个数

51 篇文章 0 订阅

可能引起死循环的解法

int numOf1(int n)
{
    int cnt = 0;
    while (n)
    {
        if (n & 1)
            ++cnt;
        n >>= 1;
    }
    return cnt;
}

把整数右移一位和把整数除以 2 在数学上是等价的,那上面的代码可以把右移运算换成除以 2 吗?答案是否定的。因为除法的效率比移位运算低得多,在实际编程中应尽可能地用移位运算代替乘除法。

为什么说,上述程序可能引起死循环呢?
如果输入一个负数,如 0x80000000,运行的时候会发生什么情况?把负数 0x8000 0000 右移一位的时候,并不是简单地把最高位的 1 移到第二位变成 0x4000 0000,而是 0xC000 0000。这是因为移位前是个负数,仍然要保持移位后也是负数,因此移位后的最高位会设为1。因此如果做右移运算,最终这个数字会变成 0xffffffff 而陷入死循环。

常规解法

为了避免死循环,我们可以不右移 n,而是左移 1。

int numOf1(int n)
{
    int cnt = 0;
    unsigned flag = 1;
    while (flag)
    {
        if (n & flag)
            ++cnt;
        flag <<= 1;
    }
    return cnt;
}

这个解法中循环的次数等于整数二进制的位数(flag << 1 左移超出整数的表示范围),32位的整数需要循环32次。下面再介绍一种算法,有多少1就只循环几次。

能给面试官带来惊喜的解法

把一个数减去1(n-1),再和原整数做与运算((n-1)&n),就会把整数最右边一个1变成0。那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。

int numOf1(int n)
{
    int cnt = 0;
    while (n)
    {
        ++cnt;
        n &= n-1;
    }
    return cnt;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

五道口纳什

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值