剑指offer之二进制位1的个数

1.求一个整数的二进制表示中有几个1

  • 基础补习:

    左移m<<n,表示m左边n位直接丢弃,同时在右侧补n个0

    右移m>>n,表示右边n位直接丢弃,负数左侧补n个1,正数和无符号数都是左侧补n个0

2.右移解法(错误的)

不断把数字右移1位,和1做&运算,判断最右侧一位是否是1
int NumberOf1(int n)
{
    int count = 0;
    while(n)
    {
        if(n&1)count ++;
        n = n >> 1; 
    }
    return n;
}
当输入负数时,右移时,每次左侧补1,死循环

3.左移解法(正确,但不是最优

int NumberOf1(int n)
{
    int count = 0;
    unsigned int flag = 1;
    while(flag)
    {
        if(n & flag)count ++;
        flag = flag << 1;
    }
    return count;
}
从右往左,依次检测n的每一位是否是1.flag由于是无符号数,当1移到最高位时,仍然有效(flag条件为true),当越过最高位时,flag全部是0,while循环结束。循环次数取决于整数的二进制位数,如果32位整数,那么循环32次

4.更优解法

  • 分析 整数n减去1,如果最后一位是1,那么最后一位设为0

    如果最后一位不是1,从右向左找,找到第一个1,设为0,然后后续位置取反,想想小学的借位减法。

    比如二进制数1100减去1,从右往左找到第一个1(红色那个),再把红色以及后面的位取反,减法后变为1011,然后1100 & 1011 = 1000刚好损失最后一个1

    总结:整数n减去1,找到从右往左第一个位置是1的位,把这个位置以及右侧按位取反

    那么n & (n-1),每次损失最右侧的一个1

  • 代码

    int NumberOf1(n)
    {
    int count = 0;
    while(n)
    {
        count ++; //能进入while,至少有个位是1
        n = n & (n-1);//损失最右侧一个1位
    }
    return count;
    }
    

    这个数有个位是1,循环几次

    5.更多应用

  • 一条语句判断一个整数是不是2的整数次方,由于2的整数次方,二进制只有一个位是1,其他位都是0,n&(n-1)之后结果必定为0

  • 两个整数m,n,求m二进制中多少个位于n不同。二进制位不同,想到异或,先求m和n的异或,mn有几个位不同,异或值就有几个位是1,然后数1的个数

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值