n!阶乘后面有多少个零

本文介绍了如何用C++计算n!阶乘尾部零的个数,通过分析2和5的因子,提出了一种在O(log n)复杂度内的解决方案,避免了大整数乘法导致的问题,适用于大规模数值的处理。

题目:计算n!中结尾零的个数(C++实现) 。

 

当时一看到这道题目便有了思路,很快就写出了代码。我写的代码如下:

 

  1. #include <stdio.h>  
  2.   
  3. /*计算n!结尾零的个数,返回零的个数。*/  
  4. int CalZeroNum(int n)  
  5. {  
  6.     int result=1;  
  7.     int num=0;  
  8.   
  9.     /*计算n的阶乘,结果保存在result中。*/  
  10.     int i;  
  11.     for(i=n;i>=1;i--)  
  12.            result*=i;  
  13.   
  14.     /*计算result结尾零的个数*/  
  15.     while(1)  
  16.     {  
  17.         if(result%10==0)  
  18.         {  
  19.             result/=10;  
  20.             num++;  
  21.         }  
  22.         else   
  23.             break;  
  24.     }  
  25.     return num;//返回零的个数。  
  26. }  
  27.   
  28. void main()  
  29. {  
  30.     printf("10!结尾零的个数为:%d/n",CalZeroNum(10));  
  31. }  

 

      面试官看了我的代码之后有些不满意,因为这种算法存在很大问题——如果n!很大时(大于32767时),int result就无法保存n!的值,程序就无法正确执行。此外,由于需要进行多次累加和累乘运算,程序的效率也是非常低的。回到宿舍后我参考了网上大牛们的算法,最后总结了几个更好的算法解决这个问题。

 

算法思想:在1-10两个数相乘要产生0,只有 10×1=2×52×5

  200=200×199×198……×2×1=2×5×2×5×2×199…. ×2×1;可以分解为质数相乘的形式,很明显有2的个数比5的多,所以只要求出200的阶乘可分解出多少个5相乘,就可得到200的阶乘结尾的连续的零的个数.

:num=[200/5]+[200/5/5]+[200/5/5/5].

: [x]表示对x取整.

所以可以通过这个思路很容易的得到任意阶乘结尾连续的零,其示例C语言代码如下:

  1. #include <stdio.h>  
  2.   
  3. /*计算n!结尾零的个数,返回结尾零的个数。*/  
  4. int CalZeroNum(int n)  
  5. {  
  6.     int num=0;//n!结尾零的个数  
  7.     int b=1;//5的次方  
  8.     while(1)  
  9.     {  
  10.         b*=5;  
  11.         num+=n/b;  
  12.         if(b>n)  
  13.             break;  
  14.     }  
  15.     return num;//返回结尾零的个数  
  16. }  
  17.   
  18. void main()  
  19. {  
  20.     printf("20!结尾零的个数为:%d/n",CalZeroNum(20));  


-----------------------------------------------分割线-----------------------------------------

上述代码怎么理解呢?他的思路是,给定n,那么先算能被5整除的数字有多少个。方法是计算n/5=a1,比如20/5=4,说明有4个被5整除的数字(5,10,15,20),然后计算n/25,统计一下被25整除的数字有多少个。。方法是n/25=a2,由于他是25啊,有两个5,所以要算两次。。。等等,被25整除的数字肯定被5整除,所以之前计算n/5的时候已经算过一次了。计算公式是N=a1 + a2*2-a2+a3*3-a3-a3...=a1+a2+a3+...就这样啦。给定n,需要循环[log5(n)+1]次,所以算法的复杂度是O(log n)的。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值