对于基础的算法很简单,很容易就能写出来。
class Solution {
public:
vector<int> countBits(int num) {
int n = num;
vector<int> ret;
for (int i = 0; i <= num; i++)
{
ret.push_back(countbit(i));
}
return ret;
}
int countbit(int num)
{
int sum = 0;
while (num!=0)
{
if (num & 1 == 1)
{
sum++;
}
num = num >> 1;
}
return sum;
}
};
但是对于进阶,需要在O(n)的时间复杂度完成。对于想要在O(n)的时间复杂度内完成,也就是你遍历一遍0-num你就能得出他们比特位里边,我们一拿到这个数不需要进行过多的计算就能知道他比特位里边有多少个1,如果我们能直接读取电脑里边的寄存器,那自然是好的,去看一下,多少个是1多少个0,但是因为有操作系统在我们是不能直接操作硬件的,这根本就是不可能实现的,所以就只能通过以前计算出来的结果来计算我当前要计算的结果,那就要从这些数字的二进制数字上边找规律
我们可以看出来,数字2n的比特位中1的个数和n中的个数是一样的,因为这只是等于n向左移动了一位,所以如果n是偶数的话,n比特位中1的个数等于n/2.但是当n是奇数的时候怎么办,当n为奇数的时候,很容易想出来,他比他的上一个偶数比特位多了一个1.所以我们就可以通过规律来求比特位1的个数。
class Solution {
public:
vector<int> countBits(int num) {
vector<int> ret;
ret.push_back(0);
for (int i = 1; i <= num; i++)
{
ret.push_back(ret[i / 2] + (i & 1));
}
return ret;
}
};
当为奇数的时候,他1的个数就是n/2加1.如果不是奇数i&1=0;就不加。
对于相邻两个数字的比特位中1的个数,无非有两种状态,n+1和n相比,要么n是偶数n+1是奇数,我的比特自然只比你多了一个1,要么n是奇数,n+1为偶数,那自然就是某一个位置会有进一位。
所以某一位数字的二进制个数F[n]=F[n&n-1]+1
class Solution {
public:
vector<int> countBits(int num) {
vector<int> ret;
ret.push_back(0);
for (int i = 1; i <= num; i++)
{
ret.push_back(ret[i&(i-1)]+1);
}
return ret;
}
};
这个规律还是比较难发现的。