C语言---求n的阶乘后面有多少个连续的0
C语言---求n的阶乘后面有多少个连续的0
题目描述:给定一个正整数n,返回n的阶乘尾部连续0的个数。
例如:(5,5*4*3*2*1=120,则返回1),(10,10*9*8*7*6*5*4*3*2*1=3628800,则返回2)
题目分析:首先拿到这道题,直接可以想到最简单的方法就是,通过循环算出这个值,然会取个位,减个位,统计一下个数即可。但是运行后就发现不可行,因为如果n稍微大一点,则算出的这个值就太大了,保存不了,且运行超时,所以这种方法不可行。
于是就得想别的方法了,最后上网查资料发现还有一种巧妙的解法,那就是将可以造成尾部出现0的情况进行分析,发现10可以由2*5造成,发现20可以由2*2*5造成,发现100可以由2*2*5*5造成。。。
多试几组数据,可以发现其规律:尾部0的个数等于min{2的个数,5的个数}
因为尾部的0是由2*5得来的,虽然也可能是4*5得来的,但是4也是由2*2得来的,所以尾部的0根本上是由2*5得来的。
这里可以发现:一对2和5可以造成尾部一个0,n对2和5可以造成尾部n个0,但是由于2可以由太多太多的数据分解得来,所以我们这里主要看5的个数主要由哪些数分解得来即可:
比如:
5!= {1 * 2 * 3 * 4 * 5} 这里只有1个5,分别是5
10!= {1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10} 这里有2个5,分别是5,10(10是由2*5组成的)
...
25!= {1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * ... * 21 * 22 * 23 * 24 * 25} 这里有6个5,分别是 5,10,15,20,25(25是由5*5组成的,所以25算2个5)
...
125!= {1 * 2 * 3 * 4 * 5 * ... * 25 * ... * 50 * ... * 75 * ... * 100 * ... * 121 * 122 * 123 * 124 * 125}这里有31个5,分别是5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,
(这里除了25,50,75,100各自是由5*5组成,算两个5,而125是由5*5*5组成的,所以125单独算三个5)
我们可以发现每隔上5个数会出现一个5,隔上25个数又单独多出来一个5,隔上125个数又单独多出来两个5...
所以我们可以这样编写代码:
①:首先可以从1 -> n隔上5个数抽取一次,获取这些数组成一个数列
②:如果上面数列的个数>=5,就再从上面数列中再隔上5个数抽取一次,获取这些数组成一个新的数列
⑤:如果上面数列的个数>=5,就再从上面数列中再隔上5个数抽取一次,获取这些数组成一个新的数列(直到获取的数列中的数的个数小于5,则停止)
例如求125的阶乘后面有多少连续的0:
这里用tmp统计5出现的个数
①:第一遍获取可以得到单5:{5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125},所以tmp = 25
②:因为其个数肯定 >= 5,所以进行第二遍获取可以得到5*5:{25,50,75,100,125},所以tmp = 25 + 5 = 30
③:因为其个数刚刚好 == 5,所以进行第三遍获取可以得到5*5*5:{125},
所以tmp = 25 + 5 + 1 = 31
④:因为其个数肯定 <=5,所以不进行第四遍获取,直接退出循环即可。
所以我们可以得到125的阶乘后面有31个连续的0
C语言代码如下:
#include <stdio.h>
int num(int n)
{
if(n < 0)//只要正整数,防止负数
{
return -1;
}
int i = 0;
int j = 5;//逐层按 5 5*5 5*5*5 进行抽取
int count = n;//统计逐次抽出了多少个数,初始值个数为总体个数
int tmp = 0;//统计5的个数
while(count >= 5)
{
count = 0;//进来后第一件事,让其先归零,重新统计抽取个数
i = 0;//进来后第一件事,也让i归零,因为i要从头开始遍历
while(i + j <= n)
{
tmp++;
i += j;
count++;
}
j *= 5;//第一遍隔5读取 第二遍隔5*5读取,下一次就是5*5*5,依次递增
}
return tmp;
}
int main()
{
printf("%d\n", num(125));
printf("%d\n", num(25));
printf("%d\n", num(12));
printf("%d\n", num(0));
printf("%d\n", num(-1));
return 0;
}
测试一下代码,结果如下:
至此,这道巧妙的题解决了。