Counting Bits

来源:互联网 发布:工业控制网络视频 编辑:程序博客网 时间:2024/06/05 06:50

Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.

Example:
For num = 5 you should return [0,1,1,2,1,2].

Follow up:

  • It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass?
  • Space complexity should be O(n).

  • Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language.
这一题意思是,给定一个数字num,求从0~num的二进制数中,分别含1的个数。如 7 = 111b,1的个数为3. 
我们当然可以很容易在O(n*sizeof(integer))时间求出,只要对于每个数我们都单独求其1的个数。
可以用__builtin_popcount (int)函数直接求,或者自己写一个函数来求(令所求数为k):
int x = 1;
count = 0;
for (int i = 0; i < 32; i++){
    count += x & k;
   k = k >> 1;
}
return count;
因为整数有32位,故用32次迭代。
有没有办法在O(n)时间里求呢?当然有。使用动态规划的方法。
下面是一个例子
当n = 7时,vector如下:
0 1 1 2 1 2 2 3
我们按照如下划分开
 1 | 1 2 | 1 2 2 3 |
分成3个区间。下一个区间大小为上一个区间的两倍。
我们定第一个区间标号为1,第二个区间标号为2。。。
2.0是第2个区间下标为0的数字,如上为1,3.2是第3个区间下标为2的数字,如上为2
我们容易发现:
3.0 = 2.0
3.1 = 2.1
3.2 = 2.0+1
3.3 = 2.1+2
同样,在第四个区间中,仍有
4.0 = 3.0       4.1 = 3.1     4.2 = 3.2    4.3 = 3.3
4.4 = 3.0+1   4.5 = 3.1+1  4.6 = 3.2+1  4.7 = 3.3+1
这个规律很容易在二进制数上进行解释,在这就不多说。
故我们得到如下规律
if (b < 上个区间大小)
    f(a, b) = f(a-1, b)
else
    f(a, b) = 1+ f(a-1, b % 上个区间大小)

我的代码如下:
vector<int> countBits(int num) {
       vector<int> res(num+1);
if (num >= 0) res[0] = 0;   //初始化最初的区间
if (num >= 1) res[1] = 1;
int base = 1;           //第一个区间的起始位置
int offset = 0;          //偏移量,f(a,b)中的b
int fore_size = 1;    //上一个区间大小
int size = 2;            //本区间大小

for (int i = 2; i <= num; i++){
if (offset < fore_size)      //b < 上个区间大小
res[i] = res[base + offset++];
else if (offset < size){     //b >= 上个区间大小
res[i] = 1 + res[base+(offset%fore_size)];
offset++;
}
else{
base *= 2;            //更换区间,前进一步
offset = 0;            //偏移量重置
fore_size = size;  //区间大小更新
size *= 2;
i--;
}
}   

return res;  
}

原创粉丝点击