输入:一个正整数n
输出:一个数组
规则:输出的数组分别表示0<=x<=n0<=x<=n0<=x<=n,范围内x的二进制表示中有多少个1。
示例:输入2,输出[0,1,1]。
分析:这道题目很直观。如果计算数字x,那就每次把x右移一位,看最后一位是不是1。
public int[] countBits(int num) {int[] answers = new int[num+1];for(int i=0;i<=num;i++){int count = 0;int r = i;for(int j=0;j<32 && r>0;j++){if(j>0){r = r>>1;}if((r & 1) == 1 ){count++;}}answers[i] = count;}return answers;}
分析2:可以考虑是不是在计算4的1个数的时候,能不能使用前面计算过的数值。4的二进制:100,右移一位就是10,我们已经计算出dp[2]=1,dp[4]=dp[2]+0。
再考虑一个奇数,例如5,二级制:101,右移一位就是10,我们已经计算出dp[2]=1,dp[5]=dp[2]+1。也就是说数值1的1的数量与i2\dfrac{i}{2}2i是有关系的。得出动态转移方程:dp[i]=dp[i>2]+(i&1)dp[i] = dp[i>2] + (i\&1)dp[i]=dp[i>2]+(i&1)。
时间复杂度降到O(n).
public int[] countBits(int num) {int[] answers = new int[num+1];for(int i=1;i<=num;i++){answers[i] = answers[i>>1] + (i&1);}return answers;}