`
周凡杨
  • 浏览: 234532 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

阶乘算法之一N! 末尾有多少个零

阅读更多

                                                                                题:给定一个整数N,求出N!末尾有多少个零,比如N=10N!=362880010!末尾有两个零。

 

首先温固一下阶乘的相关知识!

阶乘(factorial)是基斯顿·卡曼(Christian Kramp, 1760 – 1826)于1808年发明的运算符号。阶乘,也是数学里的一种术语。
任何大于1的自然数n阶乘表示方法:n!=1×2×3×……×n 或n!= n×(n-1)! 
0!=1,注意(0的阶乘是存在的).
双阶乘:
    当n为奇数时表示不大于n的所有奇数的乘积 如:7!!=1×3×5×7
     当n为偶数时表示不大于n的所有偶数的乘积(除0外) 如:8!!=2×4×6×8
     小于0的整数-n的阶乘表示:
   (-n)!= 1 / (n+1)!
   双阶乘是怎么提出来的,是根据阶乘推导出来的吗?这点百思不解?
 
然后理一下本题的解题思路:

      N个自然数相乘,结尾0的个数,依赖有多少个10相乘(有两个10相乘,结尾0的个数就为2),10=2×5,则可以理解为结尾0的个数依赖因子中2的个数和5的个数,而对于连续的自然数来说,2出现的频率比5高的多,所以最终只需要计算出因子中5的个数,即为答案。

 

   把想法整理为JAVA代码,如下所示:

 解题思路一:分析阶乘因子中的每一个数,计算其包含5的个数,最后求总和

   

private int zeroNum(int n){
      int ret = 0;
      for(int i=1;i<=n;i++){
        int j=i;
        while(j%5 == 0){
           ret++;
           j/=5;
        }
      }
      return ret;
}

 

    时间复杂度为:Nlog5N     

 

解题思路二:

f(x)表示正整数x末尾所含有的“0”的个数,则有: 
      
0 < n < 5时,f(n!) = 0; 
      
n >= 5时,f(n!) = k + f(k!), 其中 k = n / 5(取整)

 

     下面对这个结论进行证明: 
    (1)
n < 5结论显然成立。 
    (2)
n >= 5时,令n5k * 5(k-1) * ... * 10 * 5 * a,其中 n = 5k + r (0 <= r <= 4)a是一个不含因子“5”的整数。 
    
对于序列5k, 5(k-1), ..., 10, 5中每一个数5i(1 <= i <= k),都含有因子“5”,并且在区间 [5(i-1), 5i] (1 <= i <= k)内存在偶数,也就是说,a中存在一个因子“2”5i相对应。即,这里的k个因子“5” n!末尾的k“0”一一对应。 

n5k * 5(k-1) * ... * 10 * 5 * a = (5k * k!) *a

 

f(x)表示正整数x末尾所含有的“0”的个数, g(x)表示正整数x的因式分解中因子“5”的个数,则利用上面的的结论有: 

 f(n!) = g(n!) = g(5k * k!* a) =g(5k * k!)= k + g(k!) = k + f(k!) 
所以,最终的计算公式为: 
    
0 < n < 5时,f(n!) = 0; 
    
n >= 5时,f(n!) = k + f(k!), 其中 k = n / 5(取整)。 

 

 

public int method02(int n){
      int ret = 0;
      if(n<5){
        return ret;
      }
      int k = n/5;
      return k + method02(k);
}

  时间复杂度为:log5

 

 解题思路三:

    乘积末尾的0的个数依赖于因子中的2的个数和5的个数。对于阶乘来说,每2个数字就至少有一个2的因子,所以2的因子是足够的。5的因子相对少些,至少连5个数才能保证一定出现一个。注意,这里连续5个书保证出现一个5的因子是指最少的情况。比如12345,这就只会出现一个。但是考虑 212223242525 = 5 * 5,所以如果乘以25那就能得到25的因子。依次会有35的因子

    所以n!5的个数的计算是:[n/5]+[n/(5*5)]+[n/(5*5*5)]+....

 

public int method03(int n){
       int ret = 0;
       int baseNum = 5;
       while (n >= baseNum)
       {
           ret += n/baseNum;
           baseNum *= 5;
       }
       return ret;
}
时间复杂度为:log5

 

       对于解法二和解法三,我这里写的时间复杂度都为log5N  ,但实际验证,解法三比解法二更高效,所以不知道是否时间复杂度写的有问题?高人求解!!!

 

后记(顿悟):

    算法三之所以优于算法二,因为算法二是用到递归算法,递归一系列的函数调用,而函数的调用开销是很大的,系统要为每次函数调用分配存储空间,并将调用点压栈予以记录。而在函数调用结束后,还要释放空间,弹栈恢复断点。所以说,函数调用不仅浪费空间,还浪费时间。所以算法三在时间复杂度和空间复杂度上是优于算法二的。

                                                                    2013.6.20

 

参考资料:

  http://blog.csdn.net/chn_cf/article/details/6541281

  http://www.chinaunix.net/old_jh/23/926848.html

  http://www.pureweber.com/article/recursive-power-4/

 《编程之美》

  

1
4
分享到:
评论
2 楼 cherami 2017-05-15  
解法3有问题,在n很大的时候会导致baseNum溢出使得结果不对
需要把baseNum的类型改成long型
例如n的值是1808548330时,算出来是452137079,但是正确答案是452137077
1 楼 yygymmmmsee 2013-06-09  
第二和第三两个算法本质应该是一致的吧

只不过第二个使用了递归,第三个是一个循环

这也有可能是造成第二个效率比第三个低的原因

相关推荐

    n的阶乘末尾有多少个0_n的阶乘末尾的0_

    在给定的文件列表中,“n的阶乘末尾有多少个0.cpp”可能是实现这个算法的C++源代码,而“n的阶乘末尾有多少个0.exe”是编译后的可执行文件,用于直接运行程序并得到结果。 通过这种方法,我们可以有效地处理大数...

    C++版本计算n阶乘末尾0的个数原理讲解及代码实现

    本篇文章主要介绍如何使用C++编程语言来计算一个正整数n的阶乘末尾0的数量,并通过示例代码加以说明。该方法不仅阐述了理论基础,还提供了具体的实现思路。 #### 原理讲解 ##### 计算末尾0的数量 为了理解如何计算...

    n的阶乘问题--阶乘位数--阶乘末尾0的个数

    在编程领域,阶乘是一个常见的数学概念,尤其在算法和计算数学中经常被用到。本文将深入探讨“n的阶乘问题”,包括阶乘的定义、计算阶乘位数的方法以及如何确定阶乘末尾零的个数。 首先,阶乘是指一个正整数n与小于...

    100阶乘算法如何实现

    在给定的代码片段中,定义了一个名为`CalculateLargeNumber`的方法,它接受一个整数参数n,并返回一个无符号整型数组。这个方法首先检查输入值是否有效,然后初始化一个长度为100000的无符号整型数组`array`,用于...

    不要被阶乘吓倒(各种阶乘)

    阶乘定义了一个正整数 n 的阶乘 n! 为所有小于及等于 n 的正整数的乘积: \[ n! = n \times (n-1) \times (n-2) \times ... \times 1 \] 对于非负整数 n,当 n = 0 时,0! 定义为 1。阶乘的增长速度非常快,例如 10...

    用C语言实现n!最后一位非零数字的算法与程序分析.pdf

    文章通过这种算法设计和C语言实现,提供了一种解决大数阶乘末尾非零数字的有效方法,特别适合处理超出C语言基本数据类型范围的阶乘计算。这种方法对于理解和优化计算大数阶乘的算法具有重要的教学和实践价值。

    利用递归算法求阶乘(VB6.0代码编写)

    阶乘是数学中的一个概念,表示一个正整数n的所有小于等于n的正整数的乘积,通常表示为n!。例如,5! = 5 × 4 × 3 × 2 × 1 = 120。 在VB6.0中,我们可以创建一个函数来实现递归计算阶乘。下面我们将详细介绍如何...

    计算任意数阶乘的算法及实现,详细分析

    最后,主函数负责输入一个正整数n,并调用`multi_x`函数来计算n的阶乘。 ```cpp void main() { int i, n, c = 0; cout &lt;&lt; "Enter n: "; cin &gt;&gt; n; cout &lt;&lt; n ! = " ; for (i = 2; i &lt;= n; i++) multi_x(i, a); ...

    算法提高-计算超阶乘.md

    想象一下,你需要计算形如1(1+k)(1+2k)(1+3k)...(1+nk-k)的超阶乘,并准确找出其末尾0的个数以及最后一位非0的数字。这不仅考验你的数学功底,更对你的编程技巧和算法设计能力提出了高要求。 参与这个挑战,你将...

    大数阶乘算法

    在计算机科学中,大数阶乘算法是一种处理大数据量计算的算法,特别是在处理超过普通整型范围的数字乘法时,如计算一个大整数的阶乘。在本例中,我们将关注如何使用链表来实现这个算法,这种方式对初学者来说特别友好...

    求1000阶乘的结果末尾有多少个0

    3. **结束条件**:由于每次2的因子都会找到一个与之匹配的5的因子(除了那些包含额外5因子的数),我们只需要计算`count5`来确定末尾零的个数。因为对于每一对2和5,它们会产生一个10,也就是一个零。然而,由于可能...

    c语言编程题之数学问题阶乘后的0.zip

    在C语言编程中,"阶乘后的0"通常是指计算一个正整数的阶乘(n!)后,结果末尾包含的零的数量。这个问题涉及到数论中的因子分解和质因数5。我们知道,任何正整数的阶乘都会包含大量的2和5作为因子,因为2的因子总是比...

    C语言N阶乘

    本主题聚焦于使用C语言实现N阶乘的计算,其中N阶乘表示为一个正整数N的所有小于等于N的正整数的乘积(0的阶乘定义为1)。这里我们探讨的是通过链表数据结构来实现这一功能,虽然这种方法相对间接,但有助于理解链表...

    整数数组的全排算法,很经典!!!

    对于一个包含n个不同元素的数组,其全排列数量为n的阶乘(n!)。例如,数组[1, 2, 3]的全排列包括[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]。全排列算法的目标是生成所有这些排列。 常见...

    java阶乘计算获得结果末尾0的个数代码实现

    要确定一个数n的阶乘末尾有多少个零,我们需要知道在n!中有多少对因子5和2,因为每个这样的对都会在结果中贡献一个零。由于2比5多得多,通常不会成为计算的限制因素。因此,我们主要关注n中包含多少个因子5。 如...

    C++ 求任意数的阶乘

    在编程领域,阶乘是一个常见的数学运算,尤其在算法设计和计算组合数学中扮演着重要角色。本主题将深入探讨如何使用C++编程语言来计算一个整数的阶乘。阶乘定义为非负整数n的阶乘是所有小于及等于n的正整数的积,记...

    c++1000的阶乘

    2. **初始化变量**:设置一个指针指向数组末尾,表示当前结果的最低位。 3. **循环计算**:从1到1000依次进行乘法操作。 - 对于每一个乘数i,从数组的最低位开始逐位相乘。 - 如果某次相乘的结果超过了当前位能...

    【JAVA】(vip)蓝桥杯试题 基础练习 阶乘计算 BASIC-30 JAVA

    在给出的代码示例中,有两个版本,一个没有注释,一个有注释。两版代码的主要区别在于是否有注释,核心逻辑是相同的。在计算阶乘时,先读取输入的正整数n,然后调用`calculating`方法计算阶乘,使用ArrayList存储...

    刷题遇到的一些题目(Java)——持续更新

    (即阶乘)末尾有多少个0? 比如: n = 10; n! = 3628800,所以答案为2 原题链接:https://www.nowcoder.com/questionTerminal/6ffdd7e4197c403e88c6a8aa3e7a332a 算法思想:最简单的就是分解质因数 n! = n * (n-1) *...

    数据结构——用C描述

    静态链表则是在数组中模拟链表的行为,每个元素有一个整型字段`next`表示下一个元素的索引。 在链表的操作中,头指针是特别重要的。它是一个指向链表首元素的指针,用来标识整个链表。有时为了方便操作,会在链表...

Global site tag (gtag.js) - Google Analytics