原题地址:
https://oj.leetcode.com/problems/factorial-trailing-zeroes/
题目内容:
Given an integer n, return the number of trailing zeroes in n!.
Note: Your solution should be in logarithmic time complexity.
方法:
数学原理很简单,稍微讲一下
我们知道,一堆数相乘出了0,除了有0之外,需要一个2,5数对。比如4 × 5,可以分解为2 × 2 × 5,有一个2,5数对,所以有1个0。推而广之,一堆数连乘,能因式分解出几个2,5数对就有几个0。
由于在阶乘中,分解出的2肯定比5多,(要证明吗?稍微证一下。。2的倍数,也就是全体偶数在一组阶乘中肯定比5的倍数多,而只有2和5的倍数能因式分解出2,5数对来组合,因此,每一个2,5数对和数字5一一对应),因此,实际上给了我们n,我们需要找出,从1到n这个区间中,能分解出几个5。
数学原理讲完了,讲算法。
先想想,我们如何求1到n的所有5的倍数?答案很简单,n/5就可以了,因为每5个数就会有一个5的倍数。我们先把所有5的倍数个数加到结果中先。
可是这样还远远不够,因为25中能分解出2个5,而所有25的倍数都能分解出两个5,以此类推。
但我们离答案已经很近了。n/25是区间内所有25的倍数,由于25的倍数在第一轮5的倍数中,已经加了一个5,因此,这一轮也只需要加一次就行了。加上所有25的倍数的个数到结果中去,以此类推。
最后需要注意一点:乘法溢出问题。5的13次方是末尾,14次方就溢出了。
具体代码:
Python就三行,我去
class Solution: # @return an integer def trailingZeroes(self, n): l = [5 ** i for i in range(1,14)] q = [n / key for key in l] return sum(q)
C++有点多
class Solution { private: vector<int> dict; public: Solution () { int start = 5; int border = 13; for (int i = 0; i < 13; i ++) { dict.push_back(start); start *= 5; } } int trailingZeroes(int n) { int res = 0,i = 0; int p; while (i < dict.size() && (p = n / dict[i ++]) > 0) { res += p; } return res; } };
复杂度的要求毫无疑问是满足的,常数次,比log都好。