剑指offer--二进制中1的个数(位运算)

本文介绍了一种算法,用于计算输入整数32位二进制表示中1的个数,包括四种不同的实现方法:模拟二进制移位、无符号移位、位标记扫描和位清除技术。

题目描述

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

 

解题思路:四种方法。第一种对于负数是不可行的,其他三种可行。

第一种方法是模拟二进制的移位,每次循环将整数对2取余,如果不为0,代表最后一位为1,则ans++,否则最后一位为0,直接将整数除以2,类似于二进制移位操作。但是这种方法有一个弊端,就是对于int类型所能取到的最小负数,即-Integer.MAX_VALUE,没办法正确处理。

解释如下,因为int型的最小负数,换成二进制是10000....(31个0),但是在计算机中是按照补码的形式存储的,所以第一个符号位不改变,其他位取反,之后+1,得到补码为000000...(32个0)。使用这种方法是按照计算机中的补码形式计算的,因此输出的是0,而不是1,算法有漏洞。代码不写了,都很简单。

其他三种方法都是大同小异了,按照位运算进行处理,还是要注意负数的移位操作,右移时,对于负数,低位舍去,为了维护负数的表现形式,高位是需要补1的,所以也会对结果造成影响。

因此,自己的想法是,使用java中的无符号移位运算符,对整数n进行无符号移位,即向右移位时,高位补0,这样涵盖了负数在内的所有情况,代码如下:

public class Solution {
    public int NumberOf1(int n) {
        int ans = 0;
        while (n != 0) {
            if((n&0x01) != 0) // 这里特别要注意的是使用&运算符时需要将两个运算的对象用括号包起来,不然会报错误
                ans ++ ;
            n>>>=1 ;
        }
        return ans ;
    }
}

第三种,就是不让整数n进行移位操作,而是令一个二进制数,0x01依次向左移位,如果与整数n取与操作,结果不为0,代表整数n当前位置为1,ans++。代码没写,粘贴一下:

int val; // input data
int ans = 0;
int mark = 0x01;
while (mark != 0) {
    if (mark & val) ++ans;
    mark <<= 1;
}

 

第四种,举例说明:二进制数a = 1101100,

                                          (a-1) = 1101011,因此将整数依次和整数-1的值取与操作,得到的是

                                       a&(a-1) =1101000 ,每计算一次,更新整数的值并且ans++。当整数==0时,代表所有的1都已被记录。

代码如下:

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值