最近在看面试题,整理了书上的解题思路和代码,方便有需要的读者学习
题目:
输入一个非负数你,请计算0到n之间每一个数字的二进制形式中1的个数,并输出一个数组。例如,输入的n为4,由于0、1、2、3、4的二进制形式中1的个数分别是0、1、1、2、1,因此输出数组[0,1,1,2,1].
分析:
-
我们可以用i&(i-1)将二进制最右边的1变成0
代码实现:
public static int []countBits(int num){ int[]result =new int [num + 1];//用于储存0-num的1的个数 for(int i=0;i<=num;++i){//循环遍历0-num的二进制数 int j=i;//将i赋值给j while(j!=0){//每次都去最右边的一个一,直到变成0 result[i]++;//统计1的个数 j=j&(j-1);//将最右边的1变成0 } } return result; }
如果一个整数右k位,那么while循环要执行k次,因此上面代码的时间复杂度为O(nk)
-
整数i1的个数等于i&(i-1)1的个数加1
代码实现:
public static int []countBits(int num){ int[]result =new int [num + 1];//用于储存0-num的1的个数 for(int i=0;i<=num;++i){//循环遍历0-num的二进制数 result[i]=result[i&(i-1)]+1;//比去掉最右边的1的数大1 } return result; }
去掉了一个while循环时间复杂度为O(n)
-
计算i/2中1的个数
-
偶数和i/2中1的个数相同
-
奇数比i/2中1的个数多一个
代码实现:
public static int []countBits(int num){ int []result =new int [num=+1]; for(int i=1;i<=num;i++){ result[i]=result[i>>1]+(i&1); } return result; }
虽然时间复杂度也是O(n),但是位运算比求和除法更加高效