位运算+动态规划 leetcode 338 比特位计数

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

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

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

暴力破解:

class Solution {
private:
    int countNum(int num) {
        int res = 0;
        while(num >= 1) {
            if(num % 2 == 1) res++;
            num = num / 2;
        }
        return res;
    }
public:
    vector<int> countBits(int n) {
        vector<int> bits(n+1,0);
        for(int i = 0; i < n+1; i++) {
            bits[i] = countNum(i);
        }
        return bits;
    }
};

位运算的改进: 这里已经写过博客

动态规划:学习官方题解

(1)最高有效位

dp[i]表示i[数字1的个数],我们的目的是想知道是否存在j,使得通过dp[j]求出dp[i]0<=j<i

来看规律:

0-----0
1-----1
2-----1
3-----2
4-----1
5-----2
6-----2
7-----3
8-----1
9-----2
10----2
11----3
12----2
13----3
14----3
15----4
16----1

5、6、7三个数中1的个数分别是:2 2 3,刚好由1、2、3三个数中1的个数相加而来

于是,应该有:dp[i] = dp[j] + 1,

这里j的含义应该是什么呢?

我们发现:

1 = 5 - 4
2 = 6 - 4
3 = 7 - 4

显然,这里j是比数字i小的最大的2的整数次幂这个数

官方解答称:j为 i 的「最高有效位」

令k = i - j, dp[i] = dp[k] + 1

代码:

 vector<int> countBits(int n) {
     vector<int> bits(n+1,0);
     int k = 0;
     for(int i = 1; i < n + 1; i++) {
         if((i & (i-1)) == 0)  //如果这个数是2的整数次幂
             k = i; 
         bits[i] = bits[i - k] + 1;
     }
     return bits;
 }

(2)最低有效位

再来看规律:

0-----0
1-----1
2-----1
3-----2
4-----1
5-----2
6-----2
7-----3
8-----1
9-----2
10----2
11----3
12----2
13----3
14----3
15----4
16----1

规律:
(1)奇数的1的数量比它前面的偶数的1的数量多1
(2)偶数的1的数量一定和它二分之一的1的个数是一样的

  • 如果i是偶数,则bits[i] = bits[i/2]
  • 如果i是奇数,则bits[i] = bits[i-1] + 1

两种情况可以合并成:bits[i]的值等于bits[i/2]的值加上i除以2的余数,bits[i]=bits[i>>1]+(i & 1)

vector<int> countBits(int n) {
    vector<int> bits(n+1,0);
    bits[0] = 0;
    for(int i = 1; i < n + 1; i++) {
        if(i & 1) {
            bits[i] = bits[i-1] + 1;
        }
        else {
            bits[i] = bits[i/2];
        }
    }
    return bits;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值