分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请轻击人工智能教程
package live.every.day.ProgrammingDesign.CodingInterviewGuide.BitwiseOperation;
/**
* 整数的二进制表达中有多少个1
*
* 【题目】
* 给定一个32位整数n,可为0,可为正,也可为负,返回该整数二进制表达中1的个数。
*
* 【难度】
* 中等
*
* 【解答】
* 最简单的解法。
* 整数n每次进行无符号右移一位,检查最右边的bit是否为1来进行统计。
* 具体请参看如下代码中的count1方法。
*
* 如上方法在最复杂的情况下要经过32次循环,下面看一个循环次数只与1的个数有关的解法,如下代码中的count2方法。
* 每次进行n&=(n-1)操作,接下来在while循环中就可以忽略掉bit位上为0的部分。
* 例如,n=01000100,n-1=01000011,n&(n-1)=01000000,说明处理到01000100之后,下一步还得处理,因为01000000!=0。
* n=01000000,n-1=00111111,n&(n-1)=00000000,说明处理到01000000之后,下一步就不用处理,因为接下来没有1。所以,
* n&=(n-1)操作的实质是抹掉最右边的1。
*
* 与count2方法复杂度一样的是如下代码中的count3方法。
* 每次进行n-=n&(~n+1)操作时,这也是移除最右侧的1的过程。等号右边n&(~n+1)的含义是得到n中最右侧的1,这个操作在位运算的
* 题目中经常出现。例如,n=01000100,n&(~n+1)00000100,n-(n&(~n+1))=01000000。n=01000000,
* n&(~n+1)=01000000,n-(n&(~n+1))=00000000。接下来不用处理了,因为没有1。
*
* 接下来介绍一种看上去很"超自然"的方法,叫作平行算法,参看如下代码中的count4方法。
* 下面解释一下这个过程。
* 0x55555555即01010101010101010101010101010101。(n&0×55555555)+((n>>>|)&0x55555555)的结果描述了每两个
* bit成一组1的数量分布。以n=-1(111111111111111)为例进行说明,n=(n&0x55555555)+((n>>1)&0x55555555
* 为10101010101010101010101010101010,可以看到每两个bit成一组1的数量状况为10,也就是每组2个。
* 接下来,0x33333333即00110011001100110011001100110011,所以(n&0x33333333)+((n>>>1&0x33333333)就描述了
* 4个bit成一组1的数量分布。此时n=(n&Ox3333333)+((n>>>1)&0x33333333)为01000100010001000100010001000100,
* 它就代表4个bit位成一组的1数量状況为0100,也就是每组4个。
* 接下来又依次为00001000000010000000100000001000,代表8个bit位成一组1的数量状况为00001000,也就是每组8个。
* 00000000000100000000000000010000代表16个bit成一组1的数量状况为0000000000010000,也就是每组16个。
* 00000000000000000000000000100000代表32个bit成一组1的数量状况为00000000000000000000000000100000,也就是
* 每组32个。
* 类似并归的过程,组与组之间的数量合并成一个大组,进行下一步的并归。
* 除此之外,还有很多极为逆天的算法可以解决这个问题,比如MIT HackMem算法等。有兴趣的读者可以去网上查找,但对面试来说,
* 那些方法实在太偏、难、怪,所以本文不再介绍。
*
* @author Created by LiveEveryDay
*/
public class IntegerHaveHowManyOne4 {
public static int count1(int n) {
int res = 0;
while (n != 0) {
res += n & 1;
n >>>= 1;
}
return res;
}
public static int count2(int n) {
int res = 0;
while (n != 0) {
n &= (n - 1);
res++;
}
return res;
}
public static int count3(int n) {
int res = 0;
while (n != 0) {
n -= n & (~n + 1);
res++;
}
return res;
}
public static int count4(int n) {
n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);
n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);
return n;
}
public static void main(String[] args) {
int n = 8;
System.out.printf("The count of 1 is: %d", count4(n));
}
}
// ------ Output ------
/*
The count of 1 is: 1
*/