想了解更多数据结构以及算法题,可以关注微信公众号“数据结构和算法”,每天一题为你精彩解答。也可以扫描下面的二维码关注
我们知道在java语言中一个int类型有32个0或1组成。我们要计算有多少个1,这里主要以int型数据为例来分析。比如15在二进制中表示的是1111,有4个1,所以返回4。再比如16在二进制中表示的是10000,只有一个1,所以返回1。这题解法比较多,我们将会逐个分析。
一,通过移动数字计算
首先想到的是把要求的数字不停的往右移,然后再和1进行与运算,我们就以13为例画个图来分析下
看明白了上面的分析,代码就很容易多了,我们来看下代码
public int bitCount(int n) {
int count = 0;
for (int i = 0; i < 32; i++) {
if (((n >>> i) & 1) == 1) {
count++;
}
}
return count;
}
上面的分析中我们看到,如果一个数往右移了几步之后结果为0了,就没必要在计算了,所以代码我们还可以在优化一点
public int bitCount(int n) {
int count = 0;
while (n != 0) {
count += n & 1;
n = n >>> 1;
}
return count;
}
二,通过移动1来计算
上面我们使用的是把一个数字不断的往右移动,其实我们还可以保持原数字不变,用1和他进行与运算,然后通过移动1的位置来计算,这里我们判断的标准不是等于1,而是不等于0。我们还以13为例来画个图分析一下
这次我们移动的是1,我们来看一下代码
public int bitCount(int n) {
int count = 0;
for (int i = 0; i < 32; i++) {
if ((n & (1 << i)) != 0) {
count++;
}
}
return count;
}
当然我们还可以通过运算的结果是否是1来判断也是可以的,我们只需要把往左移的1和n运算完之后再往右移即可,我们来看下代码
public int bitCount(int i) {
int count = 0;
for (int j = 0; j < 32; j++) {
if ((i & (1 << j)) >>> j == 1)
count++;
}
return count;
}
三,不通过移位计算
前面两种方式要么是移动原数字,要么是移动1,这次我们不移动任何数字来计算。在位运算中有这样一个操作,就是n&(n-1)可以把n最右边的1给消掉。举个例子,当n=12的时候,我们来画个图看一下
明白了这个知识点,代码就很容易写了,我们通过循环计算,不断的把n右边的1给一个个消掉,直到n等于0为止
public int bitCount(int n) {
int count = 0;
while (n != 0) {
n &= n - 1;
count++;
}
return count;
}
我们还可以把它给为递归的写法,直接一行代码搞定
public int bitCount(int n) {
return n == 0 ? 0 : 1 + bitCount(n & (n - 1));
}
四,查表
我们还可以通过查表来计算,我们先要把0到15转化为二进制,记录下每个数字包含1的个数再构成一张表,然后再把数字n每4位进行一次计算,图就不画了,代码中有注释,我们来看下代码
public int bitCount(int i) {
//table是0到15转化为二进制时1的个数
int table[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
int count = 0;
while (i != 0) {//通过每4位计算一次,求出包含1的个数
count += table[i & 0xf];
i >>>= 4;
}
return count;
}
这题我感觉还是比较经典的,因为他的解法非常多,上面的几种要么使用循环,要么使用递归,要么是查表,其实我们还可以上面几种方式都不使用,也可以计算1的个数,这个后面会再讲。