动态规划题集

题目描述

338. 比特位计数

给定一个非负整数 num。对于 0 ≤ i ≤ num 范围中的每个数字 i ,计算其二进制数中的 1 的数目并将它们作为数组返回。

示例 1:
输入: 2
输出: [0,1,1]

示例 2:
输入: 5
输出: [0,1,1,2,1,2]

思路及代码

解法一

观察各数字的二进制代码:
0 = 0
1 = 1
2 = 10
3 = 11
4 = 100
5 = 101
6 = 110
7 = 111

2、3可以由0、1在高位处添加1得出,4、5、6、7可以由0、1、2、3在高位处添加1得出,以此类推。
换言之,[0, 1]可以推出[2, 3],[0, 3]可以推出[4, 7],[0, 7]可以推出[8, 15],…
维护一个变量range控制往前参考的距离即可。

class Solution{
   
    public int[] countBits(int num) {
   
        int[] res = new int[num + 1];
        if(num == 0)
            return res;
        res[0] = 0;
        res[1] = 1;
        int i = 2, range = 2;
        outer:
        while(true){
   
            int count = 0;
            while(count < range){
   
                if(i > num)
                    break outer;
                res[i] = res[i - range] + 1;
                count++;
                i++;
            }
            range <<= 1;
        }
        return res;
    }
}
解法二

观察一个数的二进制和它除以二后的特征。
7 = 111变为3 = 11
8 = 1000变为4 = 100
一个数除以二相当于这个数右移一位,如果这个数最低位是1,则右移后丢失一个1,于是可以得到状态转移方程:

f(n) = f(n / 2) + (n & 1)

完整代码如下:

class Solution{
   
    public int[] countBits(int num) {
   
        int[] res = new int[num + 1];
        for(int i=1;i<res.length;i++){
   
            res[i] = res[i / 2] + (i & 1);
        }
        return res;
    }
}
解法三

观察两个相邻数字的二进制代码。例如:
16 = 10000,15 = 01111, 它们进行与运算得00000
13 = 1101,12 = 1100, 它们进行与运算得1100
对于一个数,它和比他小的相邻数逐位相与,可以将其最低位的1变为0,换言之,对于一个数n,它的1的个数比n & (n - 1)多一个。
状态转移方程

f(n) = f(n & (n-1)) + 1

完整代码如下:

class Solution{
   
    public int[] countBits(int num) {
   
        int[] res = new int[num + 1];
        for(int i=1;i<res.length;i++){
   
            res[i] = res[i 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值