求 [1,num] 区间里每个整数的二进制表示所含1的个数

版权声明:本文为博主原创文章,转载需标注来源。 https://blog.csdn.net/Code_Mart/article/details/78630638

今天舍友刷题,遇到一个题目,对于某一给定数字num,求[1,num]区间里每个整数的二进制表示所含1的个数。
e.g. num = 5 则 answer[] = {1,1,2,1,2}

对这道题的最基础的解法是,对于区间里的每个整数进行移位,直到遍历该整数的二进制表示的所有位。
code:

for (int i = 1;i<=num;i++)
{
    int ans  = 0, m = i;
    for(int j = sizeof int ;j>0;j--)
        {
            ans+=(m&1); 
            m=m>>1;
        }
    answer[i] = ans;
}

这样的算法时间复杂度为O(n*sizeof int),但是有比这更好的算法,可以达到O(n)的复杂度。
回忆一下树状数组,有个操作要求给定整数的lowbit,即求该整数的二进制表示中最右侧的1的右侧所含0的个数,我们使用的办法比较简单:i&(-1)。假如最右侧1的右侧是所含0的个数为k,我们这样就可以直接求得2^k.
下面所讲的算法与其有一定的相似之处。
code:

answer[0] = 0;
for (int i = 1;i<=num;i++)
    answer[i] = answer[i&i-1] +1;

代码非常简洁,也非常容易理解。初始化边界,即answer[0] = 1。
我们知道,对于任意一个整数i而言,i的二进制表示的最右侧的1,以及从该位置起的右侧所有位置,都与i-1的二进制表示中的对应位置不同。所以,i的二进制表示中所含1的个数应为其最右侧1的左侧所有1的个数加1.

猜你喜欢

转载自blog.csdn.net/Code_Mart/article/details/78630638