码迷,mamicode.com
首页 > 其他好文 > 详细

二进制中1的个数

时间:2020-10-31 02:35:18      阅读:10      评论:0      收藏:0      [点我收藏+]

标签:方法   源码   img   --   结果   4行   lazy   stat   操作   

题目:二进制中1的个数

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

示例 1:

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

示例 2:

输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 ‘1‘。

示例 3:

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

题解:

本题主要考察的是位运算操作,作为一个搬砖的码农,解法较为普通,代码如下:

public int hammingWeight(int n) {
    //为0则直接返回
    if(n == 0) {
    	return 0;
    }
    int  bit = 1;
    int count = 0;
    //从n的低位到高位,通过循环,bit每次左移1位,即可将n的每位与 1 做一次&运算
    while(n!= bit) {
        //如果bit跟n的&运算位1,则表示当前位状态位1
        if((bit&n) == bit){
            count++;
        }
        //每次循环将n该位置0,以便判断终止条件
        n &= bit^(-1); 
        //bit左移
        bit<<=1;
    }
    return count+1;
}

这个解法的效率也不是很低,在leetcode上耗时也能击败99.5%的用户。然而在jdk源码中也有一个获取二进制1的个数的方法,看到这种解法后,不得不感叹大佬们在算法上的造诣。

源码奉上:

public static int bitCount(int i) {
    // HD, Figure 5-2
    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;
}

简简单单的6行代码-----------当然,只是步骤简单,理解起来并不是那么的容易啊??几行代码,看了我几个小时,才能懂整个过程的来龙去脉。下面谈谈我对这些代码的理解。

本题以int型为例(long、short、byte等类型解法大同小异),int型32位,也就是二进制中1的个数最多位32个(100000)占6位。
代码中的二进制表示:
0x55555555:0101 0101 0101 0101 0101 0101 0101 0101
0x33333333:0011 0011 0011 0011 0011 0011 0011 0011
0x0f0f0f0f:0000 1111 0000 1111 0000 1111 0000 1111
0x3f:	   0000 0000 0000 0000 0000 0000 0011 1111
>>>:无符号右移,以0补位
第1行代码:
i = i - ((i >>> 1) & 0x55555555);

意为将 i32位分成16组。通过将参数i 右移1位,与0x55555555 作&运算,使右移后的奇数位置零,记为i2。再将原i的值减去i2,得到结果:每组值为每组1得个数(每组2位)。

i=1111 1111 1111 1111 1111 1111 1111 1111(32位1)为例:

技术图片

技术图片

经过第1行代码运算后,16组每组1个数都为2个

第2行代码:
i = (i & 0x33333333) + ((i >>> 2) & 0x33333333);

第2行代码与1行类似,将32位分成8组,每组4位,计算结果为每4位一组的1的个数

当前 i的值为:i= 1010 1010 1010 1010 1010 1010 1010 1010

通过i & 0x33333333 求得每组低2位 1的个数,(i >>> 2) & 0x33333333 求得每组高2位1的个数,然后相加重新赋值,结果为每4位1的个数

技术图片

第3行代码:
i = (i + (i >>> 4)) & 0x0f0f0f0f;

将32位分成4组,每组8位,计算结果为每8位一组的1的个数

当前 i的值为:i=0100 0100 0100 0100 0100 0100 0100 0100

i + (i >>> 4) 计算每组高4位和低4位1的各种之和,并将高4位置零,然后重新赋值。

技术图片

第4行代码:
i = i + (i >>> 8);

将32位分成2组,每组16位,计算结果为每16位一组的1的个数

当前 i的值为:i=0000 1000 0000 1000 0000 1000 0000 1000

i + (i >>>8) 计算每组高8位和低8位1的各种之和,然后重新赋值。

技术图片

第5行代码:
i = i + (i >>> 16);

当前 i的值为:i=0000 0000 0001 0000 0000 0000 0001 0000

i + (i >>>16) 计算每组高16位和低16位1的各种之和,然后重新赋值。

技术图片

第6行代码:
return i & 0x3f;

i & 0x3f 的值为 截取i低6位的值将高26位置零。由于int型1的个数最多32个,即最多6位可表示。因此低6位的值即为i的1的个数,将其返回,求得结果。

最后,其他整型(long、short 、byte)的解法和int的解放非常相似,可以通过类似方法求解。

二进制中1的个数

标签:方法   源码   img   --   结果   4行   lazy   stat   操作   

原文地址:https://www.cnblogs.com/endless-daydream/p/13904608.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!