题目:
这题其实方法上来说,有三种。
1.暴力法就不多说了,移位计算是否为1,然后统计次数输出即可。
2.用到了前两天计算的前缀和方法。
怎么想到这个解法呢。
先写一些二进制的数,你就可以观察。
比如
0 0
1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000
以此类推
我们可以观察得出几个结论。
(1)2的指数数字处的1的个数为1
(2)每移位一次(倍增一次,2->4,4->8)才会多出一位
(3)相邻指数数字处中间1的个数可以由前面的数字相加得到。
重点解释一下第三点:
比如
3 = 2 + 1(这里的等式指的是1的数字个数)
6 = 4 + 2
7 = 4 + 3
会有这种性质是因为每一次倍增的时候,最高位是定死的,而只有后面的几位可以变动,而后面几位变动的值已经计算过了。
比如
7 111 = 1(最高位) + 11(后两位)= 100 + 011 = 4 + 3 =7
所以就可以得到一个等式。
我们用Flag表示上一个二的幂指数,NextFlag表示下一个二的幂指数
ans[i] = ans[flag] + ans[i-flag];
ans为答案数组,i为遍历下标
于是就可以得到这个算法了。
值得一提的是,这里需要初始化前两个数字,然后从2开始循环。
C++代码附带测试:
#include<iostream>
#include<vector>
using namespace std;
class Solution {
public:
vector<int> countBits(int num) {
vector<int> ans(num+1);
if(num==0)
{
return ans;
}
if(num==1)
{
ans[0] = 0;
ans[1] = 1;
return ans;
}
ans[0] = 0;
ans[1] = 1;
int flag = 1;
int nextflag = 2;
for(int i =2;i<=num;i++)
{
if(i!=nextflag)
{
ans[i] = ans[flag] + ans[i-flag];
}
else if(i==nextflag)
{
ans[i] = 1;
flag <<=1;//左移一位 相当于乘2
nextflag <<= 1;
}
}
return ans;
}
};
int main()
{
int num = 5;
Solution solution;
vector<int> ans = solution.countBits(num);
for(int i=0;i<ans.size();i++)
{
cout<<ans[i]<<" ";
}
}
3.位运算法
这个方法很神奇,没有了解过的话是不太能想到的。
这个算法的基础来自于这个式子:
n &= (n -1),可以直接清除最低位的1
为什么呢?
我们可以反过来想一想。
因为从二进制的角度讲,n相当于在n - 1的最低位加上1。举个例子,8(1000)= 7(0111)+ 1(0001),所以8 & 7 = (1000)&(0111)= 0(0000),清除了8最右边的1(其实就是最高位的1,因为8的二进制中只有一个1)。再比如7(0111)= 6(0110)+ 1(0001),所以7 & 6 = (0111)&(0110)= 6(0110),清除了7的二进制表示中最右边的1(也就是最低位的1)。
所以,凭借这个式子,相当于可以优化暴力法。并且可以想到,假如一个二进制数里面有非常多的0,需要直接计算1的个数,这个办法相当好用。
C++代码(附带测试):
#include<iostream>
#include<vector>
using namespace std;
//第一种方法
//class Solution {
//public:
// vector<int> countBits(int num) {
// vector<int> ans(num+1);
// if(num==0)
// {
// return ans;
// }
// if(num==1)
// {
// ans[0] = 0;
// ans[1] = 1;
// return ans;
// }
// ans[0] = 0;
// ans[1] = 1;
// int flag = 1;
// int nextflag = 2;
// for(int i =2;i<=num;i++)
// {
// if(i!=nextflag)
// {
// ans[i] = ans[flag] + ans[i-flag];
// }
// else if(i==nextflag)
// {
// ans[i] = 1;
// flag <<=1;//左移一位 相当于乘2
// nextflag <<= 1;
// }
// }
// return ans;
// }
//};
class Solution{
public:
int BitCount2(int n){
int sum = 0;
while(n!=0)
{
n &= (n-1);
sum++;
}
return sum;
}
vector<int> countBits(int num){
vector<int> ans(num+1);
for(int i=0;i<=num;i++)
{
ans[i] = BitCount2(i);
}
return ans;
}
};
int main()
{
int num = 5;
Solution solution;
vector<int> ans = solution.countBits(num);
for(int i=0;i<ans.size();i++)
{
cout<<ans[i]<<" ";
}
}