微软算法100题28 整数的二进制表示中1 的个数
任意给定一个32位无符号整数n,求n的二进制表示中1的个数,比如n = 5(0101)时,返回2,n = 15(1111)时,返回4
思路:
最直观的方法是对n和0001做&运算,如果结果为1,则counter加一,否则不变,然后将n右移一位,直到n=0为止. 方法count1和count2都是这种思路,其时间复杂度是n的二进制的位数
还有一种更快的方法是count3,思路是对整数n,不断清除其最右边的1,并累计计数器,直到n为0为止,这种算法的好处时其时间复杂度只和N中含有的1的个数有关
//8(1000) = 7(0111) + 1(0001) => 8(1000) & 7(0111) = 0(0000)
//7(0111) = 6(0110) + 1(0001) => 7(0111) & 6(0110) = 6(0110)
可以通过n&n-1来移除其最右边的1 为什么?因为对N的二进制来说,n的二进制等于n-1的二进制最低位加1, 如上述例子 1000=0111 + 0001 所以1000&0111=0000
0111=0110+0001,所以0111&0110=0110 (最低位被清除了)
1 package com.rui.microsoft; 2 3 public class Test28_CountBinaryOne { 4 5 public static void main(String[] args) { 6 System.out.println(count3(7)); 7 } 8 9 public static int count1(int n){ 10 if(n == 0) return 0; 11 int total = 0; 12 13 while(n>0){ 14 if((n & 1) == 1){ 15 total++; 16 } 17 n >>= 1; 18 } 19 20 return total; 21 } 22 23 public static int count2(int n){ 24 if(n == 0) return 0; 25 int total = 0; 26 for(;n>0;n>>=1){ 27 total += n&1; 28 } 29 return total; 30 } 31 32 public static int count3(int n){ 33 //可以通过不断清除最低位的1的方式来统计 n & n-1 34 //8(1000) = 7(0111) + 1(0001) => 8(1000) & 7(0111) = 0(0000) 35 //7(0111) = 6(0110) + 1(0001) => 7(0111) & 6(0110) = 6(0110) 36 if(n == 0) return 0; 37 int total = 0; 38 for(;n>0;total++){ 39 n &= n-1; 40 } 41 return total; 42 } 43 }