这是我参与更文挑战的第9天,活动详情查看:更文挑战
剑指 Offer 15. 二进制中1的个数
请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
示例
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
提示
- 输入必须是长度为 32 的 二进制串 。
个人思路解析
方式一:逐位计算
由于要计算的是二进制,那么我们就需要用到 & 运算符的特性了
- 1 & 1 = 1
- 0 & 1 = 0
通过
n & 1的运算,可以累加得到数字n中1的数量
代码
public class Solution {
public int hammingWeight(int n) {
int res = 0;
// 终止条件
while(n != 0){
// 累加 n 最后一位数值
res += n & 1;
// 右移一位
n >>>= 1;
}
return res;
}
}
提交结果
方式二:逐位运算优化
在方式一中,我们需要对数字n的二进制每一位数值都进行一个比较,这样在时间上的开销会比较大,我们可以运用n & (n - 1)这个公式,来实现一个性能的优化,该公式可以将数值n最右边的一个1转换为0,这样我们就可以跳过中间连续为0的部分了
- n: 100100
- n - 1: 100011(二进制中减一,会将最右边的
1变为0,后续的0变为1) - n & (n - 1): 100000(再通过
&运算符,将两边不同时为1的数字清0)
代码
public class Solution {
public int hammingWeight(int n) {
int res = 0;
while(n != 0){
n &= (n - 1);
++res;
}
return res;
}
}
提交结果
方式三:Integer.bitCount()
这个是java自带的一个方法,底层源码为:
public static int bitCount(int i) {
i = i - ((i >>> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
i = (i + (i >>> 4)) & 0x0f0f0f0f;
i = i + (i >>> 8);
i = i + (i >>> 16);
return i & 0x3f;
}
十六进制转换为二进制
- 0x55555555:01010101010101010101010101010101(以“1位元素”为单位,奇数为1)
- 0x33333333:110011001100110011001100110011(以“2位元素”为单位,奇数为1)
- 0x0f0f0f0f:1111000011110000111100001111(以“4位元素”为单位,奇数为1)
这里采用的是一个类似分治的思想,先以“1位元素”为单位,累加其中1的数量,得到的结果再以“2位元素”为单位,继续累加,重复计算,直至十六位(32位)。
拿到结果之后,再与0x3f做一个运算,确定最终1的个数。(0x3f:00111111 = 63)
代码
public class Solution {
public int hammingWeight(int n) {
return Integer.bitCount(n);
}
}