题目大意
给一个整数n,计算0~n每个数的二进制表示中1出现的次数。
输入
整数n,输出一个列表。例如输入5,输出[0,1,1,2,1,2]
,分别表示0,1,2,3,4,5每个数的二进制表示中1出现的次数。
要求: 时间、空间复杂度都为O(n)
思路
二进制相关题目中有一个经常用到的一个技巧,x & -x
,表示x的二进制表示中最后一个1出现的位置往后组成的数。例如x=11011100
,那么x & -x = 100
。那么x - (x & -x)
刚好比x
的二进制表示少一个1。所以对于数x,可以确定x二进制表示中1出现的次数times[x] = times[x - (x & -x)] + 1
。
不难想到对于奇数x来说,它的二进制表示中1出现的次数等于x-1
中1的次数再加1,即times[x] = times[x - 1] + 1
。当然也可以按照上面的方法计算,实际上是一样的: x - (x & -x) = x - 1, (x % 2 == 1)
。
由此,可以使用递推的方式,对奇偶数讨论,若x为
- 奇数,则
times[x] = times[x - 1] + 1
- 偶数,则
times[x] = times[x - (x & -x)] + 1
代码
class Solution {
public:
vector<int> countBits(int num) {
if (num == 0) return {0};
if (num == 1) return {0, 1};
vector<int> dp(num + 1, 0);
dp[0] = 0, dp[1] = 1;
for (int i = 2; i <= num; i++) {
if (i & 1) {
// odd
dp[i] = 1 + dp[i - 1];
} else {
// even
dp[i] = dp[i - (i & -i)] + 1;
}
}
return dp;
}
};
总结
利用(x & -x)
寻找递推关系。