zoukankan      html  css  js  c++  java
  • 剑指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。

  • 相关阅读:
    Shell变量
    Shell执行脚本
    C++类的默认成员函数
    C# CAD 二次开发(二) -集成开发环境VS2012+CAD2016
    C# CAD 二次开发(一) -前期搜集资料篇
    WPF 学习笔记(十二)
    WPF 学习笔记(十一)
    WPF 学习笔记(十)
    WPF 学习笔记(九)
    WPF 学习笔记(八)
  • 原文地址:https://www.cnblogs.com/Howfars/p/13169816.html
Copyright © 2011-2022 走看看