题目描述:
给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。
示例 1:
输入:n = 2
输出:[0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10
示例 2:输入:n = 5
输出:[0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101
提示:
0 <= n <= 105
进阶:
很容易就能实现时间复杂度为 O(n log n) 的解决方案,你可以在线性时间复杂度 O(n) 内用一趟扫描解决此问题吗?
你能不使用任何内置函数解决此问题吗?(如,C++ 中的 __builtin_popcount )来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/counting-bits
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析:
这道题比较简单,观察测试用例可以知道,是可以使用dp的。关键点在于,每次当i到达2的整数次幂(即i=1,i=2,i=4,i=8,i=16.....),此时i的二进制表示中,只有一个1。其他情况下,我们可以通过dp[i]=dp[i-pow(2,base)]+1来计算。
例如,i=17时,dp[17]=dp[16]+dp[1],16是2的4次方,因此16中只有一个1,即dp[16]=1。
而dp[1]之前已经计算过了,因此通过递推公式,就可以找到全部的答案。
详细分析请看题解:https://leetcode-cn.com/problems/counting-bits/solution/bi-te-wei-ji-shu-by-leetcode-solution-0t1i/
代码如下:
class Solution {
public:
vector<int> countBits(int n) {
vector<int> dp(n+1);
// base用来存储当前i能够到达的最大2的base次方
// 例如,i=17,则最大的2的次方为4,2^4=16,因此base=16
int base=0;
dp[0]=0;
for(int i=1;i<=n;i++)
{
// 计算2的base次方
int k=pow(2,base);
// 如果i刚好为2的base次方 则i中只有一个1
if(i%k==0)
{
dp[i]=1;
base++;
continue;
}
// 如果i比2的base次方要大,那么根据递推公式,dp[i]=1+dp[i-lastk]
else
{
int lastk=pow(2,base-1);
dp[i]=1+dp[i-lastk];
}
}
return dp;
}
};
看了看题解的答案,确实比我的要简洁很多,可以参考下。其中重要的就是可以利用i&(i-1)==0来判断i是否为2的整数次幂,这个真的是想不到。
代码如下:
class Solution {
public:
vector<int> countBits(int n) {
vector<int> dp(n+1);
// max_2_power代表当前i所能表示的最大的2的整数次幂 例如 i=17,则最大的2的整数次幂,即max_2_power为16
int max_2_power=0;
dp[0]=0;
for(int i=1;i<=n;i++)
{
if((i&(i-1))==0)
{
dp[i]=1;
max_2_power=i;
}
else
dp[i]=1+dp[i-max_2_power];
}
return dp;
}
};
tips:
vector的几种初始化方法:
1.vector<int> list; 默认初始化,最常用
2.vector<int> list={1,2,3,4,5,6,7}; 初始化list为{1,2,3,4,5,6,7}这7个元素
3.vector<int> list(7); 初始化list为7个元素的大小
4.vector<int> list(7,1);初始化list为7个元素,每个元素大小为1