【LeetCode】Factorial Trailing Zeroes

Factorial Trailing Zeroes:

Given an integer n, return the number of trailing zeroes in n!.

Note: Your solution should be in logarithmic time complexity.

 


 

 

Solution:

对n!做质因数分解n!=2x*3y*5z*...

显然0的个数等于min(x,z),并且min(x,z)==z

证明:

对于阶乘而言,也就是1*2*3*...*n
[n/k]代表1~n中能被k整除的个数
那么很显然
[n/2] > [n/5] (左边是逢2增1,右边是逢5增1)
[n/2^2] > [n/5^2](左边是逢4增1,右边是逢25增1)
……
[n/2^p] > [n/5^p](左边是逢2^p增1,右边是逢5^p增1)
随着幂次p的上升,出现2^p的概率会远大于出现5^p的概率。
因此左边的加和一定大于右边的加和,也就是n!质因数分解中,2的次幂一定大于5的次幂

 

所以,自然想到解法一:从1到n中提取所有的因子5,效率是 O(log1+log2+log3+……+logn) = O(logn!)。

 

解法二:

由上述分析可以继续发现,起作用的只有在1..n中能被5整除的那些数。而对于每一个n而言,在1..n中这样的数有 [n/5] 个。将这 [n/5] 个数从 1..n 中提出来,从小到大排成一个数列,也就是 5, 10, 15 ...  [n/5]*5。现在将这个数列所有数统一除以5(因为这个数列的长度是[n/5],而每个数都剔除一个因子5,所以计数器得到[n/5]个因子5),此时数列变成 1, 2, 3 ... , [n/5],此时问题又转化为 1..[n/5] 的平凡子问题,此时有可以将所有能被5整除的数提取出来,然后又统一剔除一个因子5,再转化为规模更小的平凡子问题……直到 [n/5]==0 问题终止。

所以对于每个阶段而言,对于 1..n,都可以统一剔除得到 [n/5] 个因子,最后递推可得解。

 

总结与升华:

实际上,相对于解法一,解法二的改进在于,对于 1..n 统计因子5的时候,把握住了连续的第 5^(c-1) 到 5^(c)-1 位置上的数,能被5整除的数它们的因子5的个数都是相同的的特点,也就是 1..4 因子5个数都是0个,5..24 因子5的个数是 1 个,25..124 因子5的个数都是 2 个…………所以一次性可以跨越一大段数来统计,而且随着 c 增大,一次跨越的数的个数越来越多,这也就是 log 函数的特点,随着 x 增大,函数增长的越来越慢,这也是 log 算法共同的特性。

 

代码如下:O(logn)

1 class Solution:

2     # @param {integer} n

3     # @return {integer}

4     def trailingZeroes(self, n):

5         ans = 0

6         while n > 0:

7             ans += n/5

8             n /= 5

9         return ans

 

 Reference:http://www.cnblogs.com/ganganloveu/p/4193373.html

 

你可能感兴趣的:(LeetCode)