位图1:位1的个数

Posted 纵横千里,捭阖四方

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了位图1:位1的个数相关的知识,希望对你有一定的参考价值。

位运算也是很重要的一个算法方向,在计算机里也是大量遇到相关问题。特别是在涉及到大数据场景下的表示、搜索和压缩存储等,位图是不可或缺的方法。

而异或和位运算几乎是天生的一对,联合起来能解决很多看似复杂的问题。不过呢,如果不专门研究一下位运算的话,可能面试官提示你用位运算来解决,你也不知道该怎么办。所以学一学还是很有必要的。我们现在先看几个例子吧。

求位1的个数

这个题目可以很简单,也可以深入到直接怀疑人生,我们就逐步递进分析这个主题。

这个问题非常重要,是理解大部分位图问题的钥匙,我们这里给出7种解法。了解了我们刷题就容易很多。

我们知道在java语言中一个int类型有32个0或1组成。我们要计算有多少个1,这里主要以int型数 据为例来分析。比如15在二进制中表示的是1111,有4个1,所以返回4。再比如16在二进制中表 示的是10000,只有一个1,所以返回1。这题解法比较多,我们将会逐个分析。

 下面的解析是摘抄的,但是找不到从哪里抄过来的了。

1 通过移动数字计算

首先想到的是把要求的数字不停的往右移,然后再和1进行与运算,我们就以13为例画个图来分析 下

 看明白了上面的分析,代码就很容易多了,我们来看下代码

 public static int bitCount(int n) {
        int count = 0;
        for (int i = 0; i < 32; i++) {
            if (((n >>> i) & 1) == 1) {
                count++;
            }
        }
        return count;
    }

测试一下:System.out.println(bitCount(3));

输出结果为2,随便换个数,都是正确的。

上面的分析可以看到,如果一个数往右移动几步之后结果为0了,就没必要在计算了,所以代码我们还可以在优化一点:

 public static int bitCount2(int n) {
        int count = 0;
       while(n!=0){
           count+=n&1;
           n=n>>>1;
       }
        return count;
    }

2 通过移动1来计算

上面我们使用的是把一个数字不断的往右移动,其实我们还可以保持原数字不变,用1和他进行与 运算,然后通过移动1的位置来计算,这里我们判断的标准不是等于1,而是不等于0。我们还以13 为例来画个图分析一下

 这次我们移动的是1,我们来看一下代码

 public static  int bitCount3(int n) {
        int count = 0;
        for (int i = 0; i < 32; i++) {
            if ((n & (1 << i)) != 0) {
                count++;

            }
        }
        return count;
    }

 当然我们还可以通过运算的结果是否是1来判断也是可以的,我们只需要把往左移的1和n运算完之 后再往右移即可,我们来看下代码

 public static  int bitCount4(int n) {
        int count = 0;
        for (int i = 0; i < 32; i++) {
            if ((n & (1 << i))>>>i ==1) {
                count++;

            }
        }
        return count;
    }

3.不通过移位计算

前面两种方式要么是移动原数字,要么是移动1,这次我们不移动任何数字来计算。在位运算中有 这样一个操作,就是n&(n-1)可以把n最右边的1给消掉。举个例子,当n=12的时候,我们来画个 图看一下:

明白了这个知识点,代码就很容易写了,我们通过循环计算,不断的把n右边的1给一个个消掉,直 到n等于0为止

  public static int bitCount5(int n) {
        int count = 0;
        while (n != 0) {
            n &= n - 1;
            count++;
        }
        return count;
    }

我们还可以把它给为递归的写法,直接一行代码搞定:

 public static int bitCount6(int n) {
        return n == 0 ? 0 : 1 + bitCount6(n & (n - 1));
    }

 4 查找

我们还可以通过查表来计算,我们先要把0到15转化为二进制,记录下每个数字包含1的个数再构成 一张表,然后再把数字n每4位进行一次计算,图就不画了,代码中有注释,我们来看下代码

 public static int bitCount7(int n) {
        //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 (n != 0) {
            count += table[n & 0xf];
            n >>>= 4;
        }
        return count;
    }

这题我感觉还是比较经典的,因为他的解法非常多,上面的几种要么使用循环,要么使用递归,要 么是查表,其实我们还可以上面几种方式都不使用,也可以计算1的个数,这个后面找机会再分析。

以上是关于位图1:位1的个数的主要内容,如果未能解决你的问题,请参考以下文章

什么是位图?

位图与布隆过滤器

位图与布隆及大数据处理题型分析

位图3:缺失数字

Java算法 -- 位图的概念和实现

Java算法 -- 位图的概念和实现