剑指offer 15、二进制中1的个数

139 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第11天,点击查看活动详情

题目:编写一个函数,其输入是一个无符号整数,要求返回二进制表达中数字位数为1的个数。

输入:n = 11 (控制台输入 00000000000000000000000000001011) 输出:3 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

但Java中没有无符号数,例如对于 11111111111111111111111111111101,其输入为-3

输入:n = 4294967293 (控制台输入 11111111111111111111111111111101,部分语言中 n = -3) 输出:31 解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

解题思路

java 中没有无符号数,也即代表我们无法直接使用除2取余法。本题看似简单,实际上考察的是对计算机底层原理的相关内容的考察,例如移位运算以及与运算等。

首先介绍移位运算,给定一个二进制数,例如0001,十进制中这个数代表1,那如果想将这个数乘2,只需要将二进制数中的最后一个1左移,依次类推,可得到2^n的结果,右移同理,相当于除法。

再说& ,只有当左右两边都为1的时候,其值才为1。那么就可以用这个性质来判断指定第几位是否为1,因为只要其它位都是0,指定为是1则可以得到值是否为0。我们也可以用这个性质来消除一个二进制数的最后一个1,即使用n & (n-1)

根据上面两个思路,可以很简单得到如下代码:

public static int hammingWeight3(int n) {
    int count = 0;
    for(int i=0;i<32;i++){
        if((n & (1<<i))!=0) count++;
    }
    return count;
}

上面的方法是按位判断每位是否为1,因为限定了数的长度为32位。时间复杂度为O(n)O(n)。另一个思路是直接一步步消除原始数的1,代码如下:

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

通过将数的末尾1一个个消除,从而得到最终的结果。时间复杂度为O(logn)O(logn)