问题:
Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also known as the Hamming weight).
For example, the 32-bit integer ’11' has binary representation 00000000000000000000000000001011
, so the function should return 3.
对于这个问题,我们首先想到是将十进制数转换成二进制的过程,通过除2取余来得到二进制的每一位来判断。然后,最容易想到的方法肯定不是最好的算法,我们可以考虑有没有比这个方法更好的算法。我们自然想到,通过移位操作要比出发操作的效率高很多。
位操作算法:首先将整数n与0x01做位与运算(&),然后将n右移移位,直到将所有位数全部移完。这种方法虽然比上一种好,但执行次数是整数的位数,那有没有一种执行次数是1的个数呢?答案是肯定的。
我们通过消除最后边的1来操作(n&=(n-1)),很多博客都介绍了这种方法,而我则侧重介绍该方法的原理:可以设想一下,假如n只有一个1的情况,做减1操作会对进行借位或者直接减掉,那么做n&(n-1)的结果则为零,因为n-1后,相对于n原来1的位置发生了改变。那么n有多个1的情况,在第一个1的左边是不会变得的,每次只会影响右边第一个1,情况和之前一样,这个,操作数就为1的个数。
代码如下,自己写了测试程序(这个小习惯可能会在你面试时写代码的时候发挥奇效呢)。
import java.util.Random; public class NumberOf1Bit { /** * 转换成2进制数,去比较每一位的值来判断是否为1 * @param n 输入的一个32位整数 * @return count 记录1的个数 */ public int hammingWeight1(int n){ int count=0; while(n!=0){ if(n%2!=0) count++; n/=2; } return count; } /** * 使用移位操作,效率要高于除法运算 * @param n * @return */ public int hammingWeight2(int n){ int count=0; while(n!=0){ if((n&0x01)!=0) count++; n>>=1; } return count; } /** * 前两个的运算次数都是每个整数的全部位,下面的方法则只需计算次数由1的个数决定 * @param n * @return */ public int hammingWeight3(int n){ int count=0; while(n!=0){ if(n!=0) count++; n&=(n-1); } return count; } public void test(){ Random r = new Random(); for(int i=0;i<10;i++){ int n=r.nextInt(50); System.out.println(n+"------"+Integer.toBinaryString(n)); System.out.println(hammingWeight1(n)+" "+hammingWeight2(n)+" "+hammingWeight3(n)); System.out.println("**********"); } } public static void main(String[] args) { // TODO Auto-generated method stub new NumberOf1Bit().test(); } }