题目:给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N=10,N!=3 628 800,N!的末尾有两个0。
方法一:
最容易想到的方法,先把N的阶乘求出来,再用一个函数计算末尾0的个数,但是这个方法有两个问题:当数字很大时,效率很差、用内置类型(int、long等)会溢出。要解决这两个问题,只能优化算法。
首先要知道N的阶乘一定可以用K×10M来表示,那我们的问题就变成了求M。又因为10 只能分解成 2 * 5,所以只需要求出 2 的个数和 5 的个数中的最小值,就得到了M。 而任何数因数分解后,2 的个数 一定多于 5 的个数(因为2的倍数比5的倍数多),所以 这个题最后又变成 了求 5 的个数。
可知 5 的倍数一定是隔 5 个数字出现一次,那么就可以修改一下循环条件不需要从1开始。
int NumOf0(int n){
int num = 0;
for (int i = 5; i <= n; i += 5){
int j = i;
/*每除得一个5,就说明末尾有一个0*/
while (j % 5 == 0){
num++;
j /= 5;
}
}
return num;
}
方法二:
上面得到了结论:求出 5 的个数就是末尾0的个数。随着数字的增加,能提取出来的 5 的个数越来越多,循环次数会增加,为了减少循环次数,我们可以提取5 , 5^2, 5^3 ……可以提高效率5 的个数 Y 可得到公式:Y = [N/5] + [N/52] + [N/53] + …
int NumOf0_fast(int n){
int num = 0;
while (n != 0){
num += n / 5;
n /= 5;
}
return num;
}类似问题:求N!的二进制表示中最低位1的位置。
这个问题相当于求N!的二进制中末尾0的个数,而对于二进制来说每乘2就会有一个0。所以问题又变成了求N!中 2 的个数。方法和上面相同,只需要把代码中的5换成2 就可以。
本文探讨如何高效地计算一个整数N的阶乘N!末尾0的个数。通过分析N!的因数分解,发现只需关注2和5的个数,特别是5的个数,因为2的个数总是大于5的。方法一是优化循环条件,从1开始每隔5个数检查;方法二是通过累加N除以5的整数部分及其更高次幂的整数部分。这种方法类比于求二进制中末尾0的个数,进一步优化了计算效率。
521

被折叠的 条评论
为什么被折叠?



