来自《编程之美》的关于阶乘的题目:
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;
}