牛客网 二进制中1的个数

基础:

1、左移运算

左移运算符m<<n表示把m左移n位。左移n位的时候,最左边的n位将被丢弃,同时在右边补上n个0。比如:

00001010<<2=00101000

10001010<<3=01010000

2、右移运算

右移运算符m>>n表示把m右移n位。右移n位的时候,最右边的n位将被丢弃。但右移时处理最左边位的情形要稍微复杂一些。如果数字是一个无符号数值,则用0填充最左边的n位。也就是说如果数字原先是一个正整数,则右移之后,直接在最左边补上n个0;如果数字原先是负数,则右移之后需要在最左边补上n个1。比如:

00001010>>2=00000010

10001010>>3=11110001

3、&和&&的区别

&:表示按位与,一般用于计算二进制的按位与运算

&&:表示逻辑与,两边都为真才是真。

题目:

输入一个整数,输出该数二进制表示中1的个数,其中负数用补码表示。

思路:

先判断整数二进制表示中最右边一位是不是1,接着把输入的整数右移,此时原来处于从右边数起的第二位被移到最右边了,再判断是不是1。这样每次移动一位,直到整个整数变成0为止。但是对于输入数据是负数的时候,会陷入死循环。因此,为了避免陷入死循环,我们可以不右移输入的数字i。首先把i和1做与运算,判断i的最低位是不是1。接着把1左移一位得到2,再和i做与运算,就能判断i的次低位是不是1......这样反复左移,每次都能判断i的其中一位是不是1。

代码:

public class Solution {
    public int NumberOf1(int n) {
        //通过每次将flag向左移动1位之后,与n进行按位&操作判断该位置是否为1
        int flag=1;
        int count=0;
        while(flag!=0){
            if((n&flag)!=0){//判断条件为&操作后的值不等于0
                count++;
            }
            flag=flag<<1;//向左移动
        }
        return count;
    }
}

厉害的做法;

思路:

如果一个整数不等于0,那么该整数的二进制表示中至少有一位是1。

1、假设这个数的最右边一位是1,则减去1之后,最后一位变成0,而其他所有位都保持不变。也就是最后一位相当于做了取反操作,由1变成0。

2、假设最后一位不是1而是0,如果该整数的二进制表示中最右边1位于第m位,那么减去1时,第m位由1变成0,而第m位之后的所有0都变成1,整数中第m位之前的所有位都保持不变。例如,1100,从0开始表示下标,则1位于2号位置,减去1之后,2号位置变为0,他后面的两位变成1,前面的1保持不变,所以结果是1011。

3、在前面两种情况中,我们发现把一个整数减去1,都是把最右边的1变成0。如果它的右边还有0的话,所有的0都变成1,而它左边所有位都保持不变。接下来我们把一个整数和它减1的结果做按位与运算,相当于把它最右边的1变成0。例如,1100,减去1之后是1011,1100与1011做按位与运算结果是1000,把1100的最右边的1变成了0,结果正好就是1000。

总结就是:把一个整数减去1,再和原来整数做与运算,会把该整数最右边一个1变成0。

代码:

public class Solution {
    public int NumberOf1(int n) {
        int count=0;
        while(n!=0){
            count++;
            n=n&(n-1);
        }
        return count;
    }
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值