Leetcode: 338.Counting Bits
题目讲的是:给定一个数字,按顺序输出范围[0,n]之间的所有整数的二进制表示中1的个数。
粗暴的做法是,历遍[0,n]。对每一个数字转化成二进制,然后一位一位地数。这个复杂度是O(n*sizeof(integer))。
题目当然想我们快点啦。希望我们在O(n)复杂度里面解决。所以是用的DP。找一下规律。我找到的规律是:
if(i%2)
{
dp.push_back(dp[i/2]+1);
}
else
{
dp.push_back(dp[i/2]);
}
解释一下,就是以0-1,2-3,4-7,8-15这样区间去考虑,发现偶数和/2的一致,奇数等于/2+1。
代码
这样就可以写了:
class Solution {
public:
vector<int> countBits(int num)
{
vector<int> dp;
if(num == 0)
{
dp.push_back(0);
return dp;
}
dp.push_back(0);
dp.push_back(1);
if(num == 1)
return dp;
for(int i=2;i<=num;i++)
{
if(i%2)
{
dp.push_back(dp[i/2]+1);
}
else
{
dp.push_back(dp[i/2]);
}
}
return dp;
}
};
按位与方法
看到我的方法打败了85%的朋友,很高兴地点开了discuss。结果发现leetcode网友打代码还是刚,一把梭。都开始比较谁写得短了……我看了一下,方法有所不同,比我这个深奥一些,总结一下就是: ret[i] = ret[i&(i-1)] + 1;
这个方程比较难理解,稍微写一下之后,大概整理思路如下:
拿到一个数n,设其表示为1100。现在希望用dp来解决,即用前面已经算出了的值来得到后面的值。那么发现dp[1100]应该是dp[1000]+1。只需要去掉一个低位的1就可以了,那么i&(i-1)这个就可以保证去掉一个低位的1(i>=1 )。所以……就可以了。
class Solution {
public:
vector<int> countBits(int num) {
vector<int> ret(num+1, 0);
for (int i = 1; i <= num; ++i)
ret[i] = ret[i&(i-1)] + 1;
return ret;
}
};