关于阶乘的问题

来自《编程之美》的关于阶乘的题目:

    1.给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N = 10, N! = 3628800,N!的末尾有两个0

    2.求N!的二进制表示中最低位1的位置。

这两道题的解法类似,先分析第二道题。

    要求得N!的二进制表示中最低位1的位置,可将N!循环右移,直到无法被2整除为止,右移的次数即为最低位1之前0的个数,因此最低位1的位置就等于(右移次数 + 1)。

    即若N = 0011(3),则 N! = 0110(6),那么N! / 2 = 0011奇数,无法继续被2整除,因此N!可右移一次,最低位1的位置等于 1 + 1 = 2(第二位) 

    所以该问题就可以转化为求 N! 的质因数 2 的个数

    关于质因数,给出一个例子:

        比如 18 = 2 * 3 * 3, 那么18的因数即为2和3, 质因数2的个数为1, 质因数3的个数为2。其中2, 3均为质数。

    那么要如何求得N!的质因数2的个数?

    在书中给出了这个一个公式:N!中含有质因数2的个数 = [N/2] + [N/4] + [N/8] + ...( [N/k] 表示1,2,3,4,...,N中能被k整除的数的个数 )

    对于这个公式,自己现在还无法给出严格的数学证明,不过似乎也可以通过实例来理解。

    例子:

        当N = 8时, N! = 8 * 7 * 6 * 5 * 4 * 3 * 2 * 1 = (2*2*2) * 7 * (2*3) * 5 * (2*2) * 3 * (2) * 1

        1 ~ 8中:

            能被2整除的数有 2, 4, 6, 8    ( 8 / 2 = 4 )

            能被2^2(4)整除的数有 4, 8    ( 8 / 4 = 2 )

            能被2^3(8)整除的数有 8    ( 8 / 8 = 1 )

        一个数能被2整除,说明该数至少含有一个质因数2。

        一个数能被2^2整除,说明该数至少含有两个质因数2。

        ……

        可以把这个公式当做是一个统计过程——比如数字8,出现了3次,说明其包含了三个质因数2;4出现了两次,即包含两个质因数2;2, 6出现了一次,即分别包含一个质因数2

        最后将每次统计的结果相加,即为总的质因数2的个数:4 + 2 + 1 = 7

那么相应的C程序为:

int lowestOne( int N )

{

    int Ret = 0;

    while( N )

    {

        N >>= 1;  //即 N = N / 2

        Ret += N;

    }

    return N;

}

那么第一题的解法也类似,即计算出N!中因数10的个数,转化为求N!中质因数5的个数。(10 = 2 * 5, 根据出现次数更少的5即可确定10出现的次数)

N!包含质因数5的个数 = [N/5] + [N/5^2] + [N/5^3]....

int NumOfZero( int N )

{

    int ret = 0;

    while( N )

    {

        ret += N / 5;

        N /= 5;

    }

    return ret;

}

原文地址:https://www.cnblogs.com/liangchao/p/2711603.html