您的位置:首页 > Web前端

剑指Offer:二进制中1的个数

2018-01-26 22:42 337 查看
请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2个1.因此如果输入9,该函数输出2。

初级解法:转成二进制统计1的个数

二进制转换规则:模二取余

将一个正数转成二进制很简单,注意遇到输入负数的情况。

public static int NumberOf1(int num){
int[] binary = new int[32];
int i=31;
boolean isNegative=false;
if(num<0){
num = -1*num;
isNegative = true;
}
while(num!=0){
binary[i] = num%2;
num = num / 2;
i--;
}
//是负数进行逐位取反再加1的操作
if(isNegative){
//逐位取反
for(int j=0;j<32;j++){
if(binary[j]==1){
binary[j]=0;
}else{
binary[j] = 1;
}
}
//加1
for(int j=31;j>=0;j--){
if(binary[j]==0){
binary[j] += 1;
break;
}else{
binary[j] = 0;
}
}
}
int counts = 0;
for(int j=0;j<32;j++){
counts +=binary[j];//将所有的1相加就是1的个数
}
return counts;
}


升级解法,但可能引起死循环

我们可以使用位移运算符将数字与1进行位运算,如果为1则统计为1,数字右移1位继续与1进行位运算,直至数字变为0。

操作流程如下图:



public static int NumberOf1(int num){
int counts = 0;
while(num!=0){
if((num&1)==1){
counts++;
}
num = num >> 1;
}
return counts;
}


如果是正数这个函数是不会有任何问题的,但是,如果输入负数呢?这个函数会进入死循环。因为负数的最高位是1,右移后要保证还是负数就应该填充1而不是0,可想而知,如果一直右移,最后这个数会变成0xFFFFFFFF。

可行常规解法

在上一版本中我们右移num导致了死循环,我们考虑不一懂它,我们去左移1,将1二进制中的1左移与num&运算。

这次的代码使用C语言实现,因为java没有无符号数:

int NumberOf1(int num){
int counts=0;
unsigned int i=1;
while(i){
if(num&i){
counts++;
}
i = i<<1;
}
return counts;
}


眼前一亮的解法(推荐)

在上一个版本中已经达到要求了,可是还是有问题,那就是num的二进制有多少位我们就要循环几次,这次我们的解法是num的二进制中有多少个1我们就循环多少次。

提示:一个数减一后的数与原数进行位运算那么它的二进制中最右侧的1就会变为0,即1的个数少一个。

例如:num(B) = 1100,它减一的结果就是1011。1100&1011后为1000,最右侧的1变为0。

基于这个思路实现代码:

public static int NumberOf1(int num){
int counts = 0;
while(num!=0){
++counts;
num = (num-1)#
}
return counts;
}


相关题目:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息