博客
关于我
剑指offer-面试题15:二进制中1的个数
阅读量:267 次
发布时间:2019-03-01

本文共 3543 字,大约阅读时间需要 11 分钟。

题目描述

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

示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’
示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1’
示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串11111111111111111111111111111101 中,共有 31 位为 ‘1’。
提示:
输入必须是长度为 32 的 二进制串 。

方法一(暴力法)

1.解题思路

直接从右向左,一次判断每一位是否为1,如果是1,则计数加1。">>>"为java的无符号右移操作。

2.代码实现

public class Solution {       public int hammingWeight(int n) {           int count=0;        while(n!=0){               if((n&1)==1){                   count++;            }            n>>>=1;        }        return count;    }}

3.复杂度分析

  • 时间复杂度:数字n的最高位1在log2n位,所以时间杂度是O(log2n)
  • 空间复杂度:不需要额外的空间开销,所以空间复杂度为O(1)

方法二(位运算)

1.解题思路

当一个数减去1,再与原数相与时,会消去最右边的1。

比如11000,减去1后是10111,相与后就变成了10000,刚好消去了最右边的1。

2.代码实现

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

3.复杂度分析

  • 时间复杂度:假设n的二进制表示中有k个1,则时间复杂度是O(k)
  • 空间复杂度:不需要额外的空间开销,所以空间复杂度为O(1)

方法三(最右1)

1.解题思路

首先我们要知道怎么获取一个数二进制的最右1,然后每获取一次,计数加1,并且原数字减去最右1作为新数字。(最右1在位运算中非常实用,树状数组的构建也有用到最右1)

怎么获取最右1呢?
先说结论,一个数和它对应的补码相与就可以得到最右1。
比如1001,反码是0110,补码是反码加1,为0111,如果是原码和反码相与,正好为0;但是由于补码有个加1操作,能将反码最右边几位调整为最右1形式,而左边部分抵消了。再比如11000,反码是00111,补码01000,补码右边部分1000正好最右1,左边部分与原码相抵消。

2.代码实现

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

3.复杂度分析

  • 时间复杂度:同方法二,假设n的二进制位中1有k个,时间复杂度是O(k)
  • 空间复杂度:不需要额外的空间开销,所以空间复杂度为O(1)

方法四(直接调接口)

1.解题思路

参考java中Integer的bitCount函数。

2.代码实现

public class Solution {       public int hammingWeight(int n) {           return Integer.bitCount(n);    }}

3.复杂度分析

  • 时间复杂度:时间复杂度为O(1)
  • 空间复杂度:空间复杂度为O(1)

方法五(bitCount源码,分治思想)

1.解题思路

0x55555555相当于01010101010101010101010101010101,0xaaaaaaaa相当于10101010101010101010101010101010,所以我们可以通过同0x55555555相与获得偶数位,同0xaaaaaaaa相与获取奇数位。类似的0x33333333为00110011001100110011001100110011,0xcccccccc为11001100110011001100110011001100,我们每4位,将二进制拆分为左右两部分,同理,也可以每8位拆分,每16位拆分,最后要获取的是16位拆分的结果。但是16拆分不能直接得出来,相当于一个递归没有到终止条件,需要经过8分,4分,2分,1分,到1分的时候,就可以直接算出来。

比如11,奇数位相与是10,偶数位相与是01,再移位相加,得到10,刚好是11中1的个数2。
JDK源码中bitCount的思路和上面是完全一致的,不过计算过程中采用了一些技巧,用尽量少的运算,来达到相同的效果。

2.代码实现

public class Solution {       public int hammingWeight(int n) {               n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >>> 1);        n = (n & 0x33333333) + ((n & 0xcccccccc) >>> 2);        n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >>> 4);        n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >>> 8);        n = (n & 0x0000ffff) + ((n & 0xffff0000) >>> 16);        return n;    }}

改进版:

public class Solution {       public int hammingWeight(int n) {           n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);        n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);        n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);        n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);        n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);        return n;        }}

JDK源码:

public class Solution {       public int hammingWeight(int n) {                   n = n - ((n >>> 1) & 0x55555555);        n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);        n = (n + (n >>> 4)) & 0x0f0f0f0f;        n = n + (n >>> 8);        n = n + (n >>> 16);        return n & 0x3f;        }}

3.复杂度分析

  • 时间复杂度:全是基本的与运算,相加,移位运算,所以时间杂度是O(1)
  • 空间复杂度:不需要额外的空间开销,所以空间复杂度为O(1)

剑指offer全集入口:

转载地址:http://stca.baihongyu.com/

你可能感兴趣的文章
mysql5.7命令总结
查看>>
mysql5.7安装
查看>>
mysql5.7性能调优my.ini
查看>>
MySQL5.7新增Performance Schema表
查看>>
Mysql5.7深入学习 1.MySQL 5.7 中的新增功能
查看>>
Webpack 之 basic chunk graph
查看>>
Mysql5.7版本单机版my.cnf配置文件
查看>>
mysql5.7的安装和Navicat的安装
查看>>
mysql5.7示例数据库_Linux MySQL5.7多实例数据库配置
查看>>
Mysql8 数据库安装及主从配置 | Spring Cloud 2
查看>>
mysql8 配置文件配置group 问题 sql语句group不能使用报错解决 mysql8.X版本的my.cnf配置文件 my.cnf文件 能够使用的my.cnf配置文件
查看>>
MySQL8.0.29启动报错Different lower_case_table_names settings for server (‘0‘) and data dictionary (‘1‘)
查看>>
MYSQL8.0以上忘记root密码
查看>>
Mysql8.0以上重置初始密码的方法
查看>>
mysql8.0新特性-自增变量的持久化
查看>>
Mysql8.0注意url变更写法
查看>>
Mysql8.0的特性
查看>>
MySQL8修改密码报错ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
查看>>
MySQL8修改密码的方法
查看>>
Mysql8在Centos上安装后忘记root密码如何重新设置
查看>>