题目
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路
可能引起死循环的解法
- 判断输入整数二进制表示中的最右边是不是1,是1计数器加一。
- 将输入整数向右移1位。
- 重复步骤1 2直到输入整数为0。
代码实现
public int NumberOf1(int n) {
int count=0;
while(n!=0)
{
if((n&1)!=0)
{
count++;
}
n=n>>1;
}
return count;
}
上述解法有一个缺陷,如果输入的是一个负数的话会陷入死循环。
常规解法
为了避免前面那个解法的死循环,我们可以不对输入的整数进行右移操作。具体思路如下:
- 将输入的整数n和1进行与运算,然后判断结果是否为1,为1的话意味着输入的整数二进制表示的最后一位是1,计数器加一。
- 将1左移一位结果记为falg,然后继续将flag和n进行与运算,然后判断结果是否为1,为1的话意味着输入整数二进制表示的倒数第二位是 1,计数器加一。
- 继续将flag进行左移一位,然后继续将flag和n进行与运算,然后判断结果是否为1,为1的话意味着输入整数二进制表示的倒数第二位是 1,计数器加一。
- 重复步骤3直到flag为0。
代码实现
public int NumberOf1(int n) {
int count=0;
int flag=1;
while(flag!=0)
{
if((n&flag)!=0)
{
count++;
}
flag=flag<<1;
}
return count;
}
上述解法中,循环的次数等于n的二进制的位数,假如n二进制位数为32,则需要循环32次。
优化算法
常规算法中,循环的次数等于n的二进制的位数。对此下面的算法对此进行优化,使得整数中有几个1就只循环几次。
- 将输入的整数n减1
- 将减1后的结果和n进行与运算,计数器加一
- 重复 12 直到n为0
经过步骤12会将n二进制中最右边的1变为0,例如1100经过步骤1和2会变成1000
代码实现
public int NumberOf1(int n) {
int count=0;
while(n!=0)
{
++count;
n=(n-1)&n;
}
return count;
}