计算出二进制数中有多少个1

来源:互联网 发布:新型网络搜索引擎 编辑:程序博客网 时间:2024/04/30 12:33
计算出二进制数中有多少个1

《编程之美》这本书被很多计算机专业的学生奉为面试经典, 其中也包括我。早就听高年级学长说过,面试中的题目有80%取自《编程之美》这本书, 掌握了其中的全部算法可以为自己的面试带来很多的好处。从今天起, 我每天更新编程之美上的一个算法, 方便想要学习的童鞋学习。

计算机专业的学生对二进制数应该都不陌生, 二进制就是由连续的有穷的0,1序列组成的数。那么, 我们的问题就来了, 现在我要统计一个01序列中有多少个1。那么, 我们应该怎么求解呢?

解法1:普通的解法,二进制数中相邻的两个数位在十进制书中参在2倍的关系。那么,我们的算法就出来了, 不断的对目标十进制数取余, 如果v%2==1, 那么证明当前的对应的二进制数位的数值为1;否则为0。算法如下:

int count(int v)

{

    int number = 0;

    while(v)

    {

        if(v%2 == 1)

        {

            number++;

        }

        v /= 2;

    }

    return number;

}

学过算法的同学应该不难分析出来,算法的复杂性是O(logv)。

解法2根据上述的算法, 我们发现上诉程序的收敛过程是目标数不断的除以2。我们知道,在计算机在运算的时候,对于除法的计算异常的复杂,所以在这里我们采用位运算。算法如下:

int count(long v)

{

    int number = 0;

    while(v)

    {

        if(v%2 == 1)

        {

            number++;

        }

        v >>= 1;

    }

    return number;

}

在这里, 我们在收敛过程中使用了位运算,提高了运行的速度。但是,因为算法本身没有发生变化,所以时间复杂度为O(logv)。

解法3:在上述的算法中, 我们的知道, 算法的复杂度就是二进制数的长度,从某种意义上讲,我们对二进制进行了一个遍历。从而得到了我们的算法和分析。但是有没有更好的?在《编程之美》中 , 书中提供了一种更为快捷的算法, 时间复杂度是O(二进制数中1的个数)。

那么,写这本书的大神是怎么想出来的呢?我想思路主要有以下的几点:

(1)从算法的最有复杂度考虑:算法的最优的复杂度当然是O(1),但是这道题显然不能, 所以我们想到了下一个算法复杂度O(logN),这个复杂度是我们第一个解和第二个解的复杂度, 所以我们立马想到, 再优的算法当然就是在O(m)(m为二进制中的1的个数).

(2)有了上面的分析, 那么我们就要构造出这个算法。想要达到这个算法复杂度, 我们就必须对二进制数进行必要剪枝,所谓剪枝就是减去掉二进制数中的0。那么怎么去掉呢?我们来分析以下二进制的构成:

                                                            0x1100010101000

在上诉这个二进制数, 我们可以看到0,1交替出现,当我们用这个数减去一个1的时候, 我们发现最这个数最大的影响就是这个数的最后一一个1变为了0, 并且这个1后面全部的0变为了1, 于是我们可以想到对数进行“与”操作, 去掉受影响的部分,这样下去直到整个目标数变为0.算法复杂度还真就达到了上述的目标复杂度。

算法如下:

int count(long v)

{

    int number = 0;

 

    while(v)

    {

        v &= (v-1);

        number++;

    }

    return number;

}

呵呵, 是不是很爽, 算法的魅力就在这里,我们可以用各种稀奇古怪的东西对计算的过程进行一系列的优化。

                

原创粉丝点击