《剑指Offer》面试题15. 二进制中 1 的个数

题目描述

面试题15. 二进制中1的个数

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

示例 1:

  • 输入:00000000000000000000000000001011

  • 输出:3

  • 解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 ‘1’。

示例 2:

  • 输入:11111111111111111111111111111101

  • 输出:31

解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1’。

解题思路

思路一: 逐位判断

解法一:按位与

作者:jyd

来源:力扣(LeetCode)

按位与运算符 &

参加运算的两个数据,按二进制位进行运算

  • 运算规则:0&0=0;0&1=0;1&0=0;1&1=1;

根据运算定义,设二进制数字n,则有:

  • 若 n & 1 = 0,则二进制最后一位为0;

  • 若n & 1 = 1 ,则二进制最后一位 为 1

可能会有一些小困惑,为什么9 & 1 = 110 & 1 = 0?数字在计算机存的是补码,而按位与是相同为1,不同为0。和1与完之后,源数字的二进制位并没有发生变化(如果是|就变了),因此,我们只需要逐位缩短判断即可!


根据以上特点,考虑以下循环判断

  1. 判断n最后一位是否为1,根据结果计数。

  2. 将n右移一位(本题要求把数字n看作无符号数,因此使用无符号右移操作)

算法流程

  1. 初始化数量统计变量res = 0

  2. 循环逐位判断:当n = 0时跳出

    • res += n & 1; 若n & 1 = 1,则统计数res加。

    • n >>= 1;将二进制数字n无符号右移位(Java中无符号右移为>>>

  3. 返回统计数量res

public static int hammingWeight(int n) {
    int count = 0;
    while(n != 0) {
        if((n & 1) != 0) {
            count++;
        }
        n = n >>> 1;
    }
    return count;
}
解法二:字符比较

将数字转换为二进制的字符串,拿到每一位和字符1作比较

  • 读取字符串的每一位charAt()【无解】

  • 转换为字符数组(浪费空间,空间复杂度为O(n))

踩坑:

将给定的二进制数00000000000000000000000000001011转换为字符串时,会出现问题

int n = 00000000000000000000000000001011;
String str = n + "";

打印str为:521。由于我比较菜,还不知道为什么是这样?知道的大佬告知一下哈!

思路二:巧用 n & (n−1)

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

算法流程

  1. 初始化数量统计变量res
  2. 循环消去最右边的1:当=0时跳出
    • res+=1:统计变量加1;
    • n&=n-1:消去数字n最右边的1。
  3. 返回统计数量res
public static int hammingWeight(int n) {
    int count = 0;
    while(n != 0) {
        count++;
        n &= n - 1;
    }
    return count;
}

思路三:使用Integer类提供的方法

解法一:toBinaryString()

【toBinaryString()方法分析】

  • 以二进制(基数 2)无符号整数形式返回一个整数参数的字符串表示形式。
  • 如果参数为负,该无符号整数值为参数加上 2^32;否则等于该参数。

因为Java里的int是有符号的,在内存中没有正负之分,只有0/1,整数是用补码表示的

正数补码等于原码

负数的补码等于其绝对值的反码+1,正好等于自身+2^32(对于4字节的整型来说)

-1 的补码 就是 绝对值1 的反码(按位取反) `11111111 11111111 11111111 11111110

+1,等于

11111111 11111111 11111111 11111111

这样正好能把最高位为1的数字用来表示负数,而最高位为0的数字表示非负数

10000000 00000000 00000000 00000000 => -2147483648

11111111 11111111 11111111 11111111 => -1

00000000 00000000 00000000 00000000 => 0

00000000 00000000 00000000 00000001 => 1

01111111 11111111 11111111 11111111 => 2147483647

因此负数+2^32之后的二进制串,就是该负数内存中准确的存储形式

此题只是针对无符号数

Integer.toBinaryString(n).replaceAll("0", "").length(); 把一个10进制数转为32位的2进制数,将0替换为空字符返回

解法二:bitCount()

Integer.bitCount(n) 统计二进制数中 1 的个数

此方法的源码:

此方法的源码分析参考文章:Integer.bitCount()理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值