Factorial-Trailing-Zeroes
来自LeetCode的第172道算法题Factorial Trailing Zeroes:
Given an integer n, return the number of trailing zeroes in n!.
Note: Your solution should be in logarithmic time complexity.
即给一个整数 n
, 给出 n
的阶乘 n!
中有多少个 0,要求算法时间复杂度是 O(log(n))
思路
看到题目后,有人直接拔“刀”切“菜”,先 ‘%’ 再 ‘/‘ ,各种挥舞之后,发现提示 “Out of Range” 的错误,然后绞尽脑汁,回忆各种数据结构与算法,尝试是否能够尽快“吞”下,最后发现还是被“噎”住了:(
要拿下这个题目,要考验基本数学功底了。。。看了网上许多分析解决的思路,觉得陆草纯的分析很透彻,思路原来酱紫的。
证明
对 n!
做质因数分解 n! = 2^x * 3^y * 5^z * ...
由于所有的质因数中,只有2 * 5
得到的结果中才会有 0 出现,因此,只需要根据质因数 2 或 5 的幂次就可以知道 0 的个数了,那么,到底是 2 的幂次,还是 5 的幂次才是 0 出现的个数呢?
显然 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
的概率会远大于出现2^p
的概率。
即 2 的各个幂次的加和一定大于 5 的各个幂次的加和,也就是 n!
质因数分解中,2 的次幂一定大于 5 的次幂;)
解法 1
1 | int trailingZeroes(int n) { |
解法1还有优化的空间…….
解法 2
根据上面的证明过程分析可以看出,起作用的只有被5整除的那些数。能不能只对这些数进行计数呢?
存在这样的规律:[n/k]
代表 1~n
中能被 k
整除的个数。有一点要注意的就是25这种,5和5相乘的结果,所以,还要看 n/5
里面有多少个5,也就相当于看n里面有多少个25,还有125,625…..
1 | int trailingZeroes(int n) { |
看到解法2这么简洁优美的代码,我已经醉了…
总结
数学功底很关键,很重要!
突然想到“我是歌手3”里歌手李健看到数字 2 后,第一个反应是 “2 是质数里面的第一个啊,挺好的”,也是醉了;)