剑指 Offer II 003. 前 n 个数字二进制中 1 的个数

创建时间: November 24, 2021 9:59 AM
最后编辑时间: November 24, 2021 2:03 PM
标签: 位运算, 动态规划
网址: https://leetcode-cn.com/problems/w3tCBm/
难度: 简单

题目

输入一个非负数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的个数

计算整数的二进制形式中 1 的个数

计算整数i的二进制形式中1的个数的一种比较高效的方法是每次用i&(i-1)将整数i的最右边的1变成0。整数i减去1,那么它最右边的1变成0,而其左边所有位都保持不变,如果它的右边还有0,则右边所有的0都变成1。下面对i和i-1进行与运算,相当于将其最右边的1变成0。

以二进制的1100为例,它减去1的结果是1011。1100和1011的与运算的结果正好是1000。二进制的1100最右边的1变为0,结果刚好就是1000。

class Solution {
    public int[] countBits(int n) {
       int[] res=new int[n+1];
        for(int i=0;i<=n;i++){
            res[i]=oneBits(i);
        }
        return res;
    }
    //计算整数的二进制形式中1的个数
    public int oneBits(int num){
        int res=0;
        while(num!=0){
            num=num & (num-1);
            res++;
        }
        return res;
    }
}

使用动态规划

题目要求计算一个连续整数序列的二进制1的个数,因此可以利用已经计算出的结果来计算当前数的结果。已知i&(i-1) 是将i 的二进制形式中最右边的1变成0,也就是说,整数i的二进制形式中1的个数比i&(i-1)的二进制形式中1的个数多1。因此有以下表达式

\[dp[i] = \begin{cases} 0, & i=0 \\ dp[i\&(i-1)]+1, & i\geq1 \end{cases}\]

class Solution {
    public int[] countBits(int n) {
        int[] result=new int[n+1];
        for(int i=1;i<=n;++i){
            result[i]=result[i&(i-1)]+1;
        }
        return result;
    }
}
posted @ 2021-11-24 14:12  卡西西  阅读(100)  评论(0)    收藏  举报