(力扣—动态规划)比特位计数
要求
给定一个非负整数 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)的意义:
当前数据与上一个数据相与时可以分成两个步骤进行:
当产生进位时:
- i中的0去掉i - 1中所有不需要的1
- i中进位上来的1会被上一个数据去掉
所以相与的结果中1的个数是i中1的个数减1
当不产生进位时:
- i中的0去掉i - 1中所有不需要的1(这种情况没有去掉)
- 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;
}
};