剑指Offer_#15_二进制中1的个数

剑指Offer_#15_二进制中1的个数

Contents

题目

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。

示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

思路分析

方法1:循环移位计数

算法流程

  1. 初始化计数变量res=0
  2. 循环右移位并判断每一位是否是1,当n=0时跳出
    * n与1进行与运算,相当于取出当前的末位数,如果结果为1,res增加1
    * n右移移位(注意在java中需要使用无符号右移>>>)
  3. 返回结果

编码时要注意的点

  1. &操作符与==操作符的优先级问题
    由于==操作符的优先级大于&操作符,所以在进行判断时,需要在与运算外加括号,即
    if ((n & 1) == 1) res += 1;//由于&的优先级低于==,n & 1外边需要加括号

运算符优先级
运算符优先级

  1. 有符号数和无符号数
    题目要求我们将输入的n看作无符号数,即没有符号位,只能表示0或者正数。
    但是在java中却是将输入的n看作有符号数的,java中的基本类型都是有符号数,也就是将第一位作为符号位,1表示负数,0表示正数。
    所以在代码中有两个地方需要特别注意:
    1. 循环条件需写成n != 0,而非n > 0,因为输入的测试用例中有一些以1开头的,java编译器将其视为负数,所以如果用n > 0作为判断条件,输入以1开头的数字,输出总是为0,是错误的。
    2. 右移操作,应该使用无符号右移操作符>>>而非普通右移操作符>>
      • 右移>> :该数对应的二进制码整体右移,左边的用原有标志位补充,右边超出的部分舍弃。
      • 无符号右移>>> :不管正负标志位为0还是1,将该数的二进制码整体右移,左边部分总是以0填充,右边部分舍弃。
        如果使用普通右移,对于负数,会在左边补1,那么就增加了原本数字里边1的个数。这样一来,永远都会有新的1出现,循环无法跳出,提交结果是超出时间限制。

方法2:n & (n-1)

(n−1) 解析: 二进制数字 n 最右边的 1变成 0 ,此 1 右边的 0 都变成 1 。
n&(n−1) 解析: 二进制数字 n 最右边的1 变成 0 ,其余不变。

图解
图解

也就是,每次进行n & (n - 1)运算,就可以消去最后一位的1。
通过循环,每一次消去一位1,就计数一次,最后n变为0,循环结束。

解答1:循环移位计数

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int res = 0;
        while(n != 0){//这里条件写为n > 0就不能通过,因为如果首位为1,那么这是一个负数,不会进入循环
            if ((n & 1) == 1) res += 1;//由于&的优先级低于==,n & 1外边需要加括号
            n = n >>> 1;//>>>的意思是右移之后,左边补零
        }
        return res;      
    }
}

复杂度分析

时间复杂度为,因为输入n,对应的二进制数位数是
空间复杂度为,使用额外变量res

解答2:n & (n - 1)

public class Solution {
    // you need to treat n as an unsigned value
    public int hammingWeight(int n) {
        int res = 0;
        while(n != 0){
            n = n & (n - 1);
            res++;
        }
        return res;      
    }
}

复杂度分析

时间复杂度为,M为1的个数。
空间复杂度为,使用额外变量res。

原文地址:https://www.cnblogs.com/Howfars/p/13169816.html