402,位1的个数系列(三)

402,位1的个数系列(三)

Yesterday is history. Tomorrow is mystery. But today is a gift.

昨日已逝,明天尚远,今天才是老天赐予的礼物。 

问题描述

之前我们有两篇是讲了位1的个数,没看过的可以看下,364,位1的个数系列(一),385,位1的个数系列(二)。其中上一篇我们没有使用for循环以及while循环,使用的是相加的方式,今天我们讲的是和上一题非常相似的解法,相减的方式。

 

每两位存储

比如我们用两位数字存储的时候,我们只需要用这两位数减去偶数位上的值(从右往左数),比如

  • 二进制00:00-0=00(表示有0个1)

  • 二进制01:01-0=01(表示有1个1)

  • 二进制10:10-1=01(表示有1个1)

  • 二进制11:11-1=10(表示有2个1)

我们发现除了第一步和《位1的个数系列(二)》不同以外,其他的我们都可以完全按照上一题的方式来写,我们还是以-3为例来画个图看一下

 

402,位1的个数系列(三)

 

402,位1的个数系列(三)

上面的分析如果能够看的懂的话,那么代码就容易多了,我们来看下

1public static int bitCount(int i) {
2    i = i - ((i >>> 1) & 0x55555555);
3    i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);
4    i = (i + (i >>> 4)) & 0x0f0f0f0f;
5    i = i + (i >>> 8);
6    i = i + (i >>> 16);
7    return i & 0x3f;
8}

具体细节就不再这里分析了,如果想了解更多可以看《位1的个数系列(二)

 

每3位存储

我们两位能存储,那么3位呢,看过《位1的个数系列(二)》的都知道,这也是可以的,之前我们介绍过的是通过一个个相加,也很好理解,那么这里如果使用的是相减应该怎么计算呢,我们来画个图看一下吧

 

402,位1的个数系列(三)

 

通过上面的图分析我们找到了规律,就是每3位存储的话,只需要执行a=a-(a>>>1)-(a>>>2)就可以把数字存储到这3位数中,原理很简单,我们来看下代码

1public static int bitCount(int n) {
2    n = n - ((n >>> 1) & 033333333333) - ((n >>> 2) & 011111111111);
3    n = ((n + (n >>> 3)) & 030707070707);
4    n = ((n + (n >>> 6)) & 07700770077);
5    n = ((n + (n >>> 12)) & 037700007777);
6    return ((n + (n >>> 24))) & 63;
7}

结果对不对,我们只有找几组数据经过测试之后才具有说服力,我们顺便找几组数据测试一下

 1    int num = 100000000;
2    System.out.println(num + " 的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
3    num = Integer.MAX_VALUE;
4    System.out.println(num + "的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
5    num = 0;
6    System.out.println(num + "   的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
7    num = -1;
8    System.out.println(num + "  的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
9    num = Integer.MAX_VALUE - 10000;
10    System.out.println(num + "  的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
11    num = Integer.MIN_VALUE;
12    System.out.println(num + "的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));

我们再来看一下打印结果

1        100000000 的二进制是----->00000101 11110101 11100001 00000000 ---->1的个数是:12
2        2147483647的二进制是----->01111111 11111111 11111111 11111111 ---->1的个数是:31
3        0   的二进制是----->00000000 00000000 00000000 00000000 ---->1的个数是:0
4        -1  的二进制是----->11111111 11111111 11111111 11111111 ---->1的个数是:32
5        2147473647  的二进制是----->01111111 11111111 11011000 11101111 ---->1的个数是:26
6        -2147483648的二进制是----->10000000 00000000 00000000 00000000 ---->1的个数是:1

结果丝毫不差。

 

每多位存储

看明白了上面每3位存储的分析过程,那么这题解法就比较多了,我们可以类推每4位存储的时候我们只需要执行a=a-(a>>>1)-(a>>>2)-(a>>>3),就可以把每4位1的个数存储在这4位数中,同理每5位存储的时候我们只需要执行a=a-(a>>>1)-(a>>>2)-(a>>>3)-(a>>>4),就可以把每5位1的个数存储在这5位数中。每6位的时候……,那么这样写下去就非常多了。我们就分别以每4位和每5位为例来写一下。首先写的是每4位为一组来存储

1public static int bitCount(int n) {
2    int tmp = n - ((n >>> 1) & 0x77777777) - ((n >>> 2) & 0x33333333) - ((n >>> 3) & 0x11111111);
3    tmp = ((tmp + (tmp >>> 4)) & 0x0f0f0f0f);
4    tmp = ((tmp + (tmp >>> 8)) & 0x00ff00ff);
5    return ((tmp + (tmp >>> 16)) & 0x0000ffff) % 63;
6}

再来看一个每5位为一组来存储

1public static int bitCount(int n) {
2    n = n - ((n >>> 1) & 0xdef7bdef) - ((n >>> 2) & 0xce739ce7) - ((n >>> 3) & 0xc6318c63) - ((n >>> 4) & 0x02108421);
3    n = ((n + (n >>> 5)) & 0xc1f07c1f);
4    n = ((n + (n >>> 10) + (n >>> 20) + (n >>> 30)) & 63);
5    return n;
6}

我们随便找几组数据测试一下

 1    int num = 1000;
2    System.out.println(num + " 的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
3    num = Integer.MAX_VALUE;
4    System.out.println(num + "的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
5    num = 0;
6    System.out.println(num + "   的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
7    num = -1;
8    System.out.println(num + "  的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
9    num = -8;
10    System.out.println(num + "  的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));
11    num = Integer.MIN_VALUE;
12    System.out.println(num + "的二进制是----->" + Util.bitInt32(num) + "---->1的个数是:" + bitCount(num));

我们就用最后一个每5位为一组的来测试一下,来看下结果

1        1000 的二进制是----->00000000 00000000 00000011 11101000 ---->1的个数是:6
2        2147483647的二进制是----->01111111 11111111 11111111 11111111 ---->1的个数是:31
3        0   的二进制是----->00000000 00000000 00000000 00000000 ---->1的个数是:0
4        -1  的二进制是----->11111111 11111111 11111111 11111111 ---->1的个数是:32
5        -8  的二进制是----->11111111 11111111 11111111 11111000 ---->1的个数是:29
6        -2147483648的二进制是----->10000000 00000000 00000000 00000000 ---->1的个数是:1

结果完全正确

 

总结

我们通过这3个系列,算是把这道题完全讲透了,这题虽然看似简单,但其中蕴含的解题思路确是非常多的,如果这题的所有解法都看懂了,那么对二进制的掌握程度将会有一个很大的提升。

 

 

402,位1的个数系列(三)

385,位1的个数系列(二)

364,位1的个数系列(一)

361,交替位二进制数

338,比特位计数

 

 

402,位1的个数系列(三)

长按上图,识别图中二维码之后即可关注。

 

如果喜欢这篇文章就点个"赞"吧

上一篇:leetcode — 402. 移掉 K 位数字


下一篇:【图像处理】基于matlab鼠标画图【含Matlab源码 402期】