Java面试题——前n个数字二进制形式中1的个数

题目:输入一个非负数n,请计算0到n之间每个数字的二进制形式中1的个数,并输出一个数组。例如,输入的n为4,由于0,1,2,3,4的二进制形式中1的个数分别为0、1、1、2、1,因此输出数组【0,1,1,2,1】

对于很多人最先想到的暴力解法,就是使用一个for循环从0到n的每个整数i的二进制形式中1的个数。于是问题转换成如何求一个整数i的二进制形式中1的个数。

高效方法: 每次采用“i & (i-1)"将整数i的最右边的1变为零。整数i减去1,那么它最右边的1变成零。如果他的右边还有零,则右边所有的零都将变成1,而其左边的1变成零,以二进制的1100为例它减去1的结果为1011,1100和1011的位与运算正好是1000.二进制的1100最右边的1变为零,刚好结果就是1000.

public int[] countBits(int num){
    int[] result = new int[num+1];//存储第i位1的数目
    for(int i = 0; i <= num; i++){
        int j = i;
        while (j !=0){//判断所有的1是否都转变为零
            result[i]++;
            j = j & (j -1);//将最后一个一的位置变为零
        }
    }
    return result;
}

代码优化:分析可知,”i & (i - 1)”将i的二进制形式中最右边的1变成0,也就是说,整数i的二进制形式中1的个数比“i & (i - 1) "的二进制形式中1的个数多1.

public int[] countBits(int num){
    int[] result = new int[num+1];//存储第i位1的数目
    for(int i = 0; i <= num; i++){
        result[i] = result[i & (i-1)] + 1;
    }
    return result;
}

另外一种方法:根据“i/2“计算i的二进制形式中1的个数:

        如果正整数i时一个偶数,那么i相当于将”i/2“左移一位的结果,因此偶数i和”i/2"的二进制形式中的1的个数是相同的。如果i时奇数,那么i相当于将“i/2”左移一位后再加一,所以奇数i的二进制形式中1的个数比“i/2”多一个1。

public int[] countBits(int num){
    int[] result = new int[num+1];//存储第i位1的数目
    for(int i = 0; i <= num; i++){
        result = result[i>>1] + (i&1);
    }
    return result;
}

此代码段采用了“i>>1”计算“i/2”,用“i & 1”计算“i%2”。

猜你喜欢

转载自blog.csdn.net/lijingxiaov5/article/details/122187539