(力扣---动态规划)比特位计数

(力扣—动态规划)比特位计数

要求

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

示例 1:

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

示例 2:

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

思想

这道题要计算二进制中1的个数,那我们就想能不能用二进制进行运算(ps:这里多说一句 二进制真的太奇妙了)
为了方便解释接下来的思想,下面列举0 - 5的对应二进制数

0000 0
0001 1
0010 2
0011 3
0100 4
0101 5

前面是对应四位二进制数 后面是对应十进制数

我们先说一下解决这个算法的整体思想
初始化一个dp数组,在计算当前位数据中1的个数时 设法利用之前的结果来推出当前数据1的个数,直到运行结束

然后观察上面给的五个二进制数据,我们会发现 每加1,会使上一个数中的有些1变成0,反之有的会变成1。利用位运算解决这道题的根本是要理解为什么加1后上一个数据有的1变成0,有的0变成1,下面分两部分解释:
(1). 1变成0
前一个二进制数据1变成0的原因是,在此位产生了进位,当前数据不需要此位上的1了。

(2). 0变成1
0变成1有两种情况:
1). 在不产生进位的情况下,仅仅是上一个数据加了1的原因
2). 产生进位时,当前数据会将上一个数据中所有不需要的1去除后,在上一个数据原本是0的位上加1,也就是进位。

i & (i - 1)的意义:
当前数据与上一个数据相与时可以分成两个步骤进行:

当产生进位时:

  1. i中的0去掉i - 1中所有不需要的1
  2. i中进位上来的1会被上一个数据去掉
    所以相与的结果中1的个数是i中1的个数减1

当不产生进位时:

  1. i中的0去掉i - 1中所有不需要的1(这种情况没有去掉)
  2. i中进位上来的1会被上一个数据去掉(这种情况所说的进位就是加的1)
    所以结果也是i中1的个数减1

综合考虑后可以发现,如果进行i & (i - 1)的运算,其结果会先去掉i - 1中所有不需要的1,然后会去掉新加的1,所以i中1的个数是相与结果加1

python code
class Solution:
    def countBits(self, num: int) -> List[int]:
        dp = [0] * (num + 1)
        for data in range(1, num + 1):
            dp[data] = dp[data & (data - 1)] + 1
        return dp
c++ code
class Solution {
public:
    vector<int> countBits(int num) {
        vector<int> dp(num + 1);
        for(int i = 1; i <= num; i++)
            dp[i] = dp[i & (i - 1)] + 1;
        return dp;
    }
};

你可能感兴趣的:(动态规划)