剑指offer面试题10:二进制中1的个数

题目:请实现一个函数,输入一个整数,输出该二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1,因此如果输入9,该函数输出2。

常规的解题思路:

可以把n和1做与运算,如果结果为1,那么n的最后一位为1,否则为0,然后n右移1位,再和1做与运算,直到判断完n的所有位。

int statisticsNums(int n)
{
    int sum=0;
    while(n)
    {
        if(n&1)
        {
            sum++;
        }
        n=n>>1;
    }
    return sum;
}
上面代码当传入的参数为正数,能够返回正确的值,但传入的参数为负数时,就会陷入死循环,函数没有办法返回值。原因分析:

我们来看一下左移和右移运算的法则:

左移(<<):左移n位,高位舍弃n位,低位补n个0

右移(>>):右移n位,低位舍弃n位,当数为正数时,高位补n个0,当数为负数时,高位补n个1。因为在计算机组成原理中,符号位1表示负数,符号位0表示正数。

举两个栗子:

1.3<<2

假设整数3为int类型,那么它占4个字节,也就是有32位,表示如下:

左移两位后结果应该是这样:

3<<2=12

2.9>>1

9的二进制位:

9右移1位:

9>>1=4

可以看出来,在数学意义上,左移n位代表乘以2的n次方,右移n位代表除以2的n次方。

我们再来看一下计算机组成原理中是如何表示一个负数的。

在计算机中为了减少操作,一般用数的补码来表示一个数。

正数的补码=原码

负数的补码=负数正值的原码取反+1

比如计算-9的补码过程:

剑指offer面试题10:二进制中1的个数_第1张图片

所以-9的二进制补码用16进制表示为0xFFFFFFF7,

回到上面的问题,假设给函数传入的参数为-9,那么当-9经过4次右移1位后,结果将变成

结果用16进制表示就是0xFFFFFFFF,所以程序最终会陷入死循环。

为了避免死循环的出现,我们可以不让n移动,而每次让1左移1位,这样结果也是一样的。

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



你可能感兴趣的:(数据结构和算法学习笔记)