首先基于一个事实:咱们不可能真的把 n! 的结果计算出来,再去数结果的末尾有几个0;n 很小还好,若是n很大,甚至趋近于无穷大,咱们是不可能这样作的。缘由主要有二:java
连计算机都算不出来,那咱们怎么办呢?别慌,虽然咱们不能直接算出结果,但咱们能够把问题一步步拆解。算法
首先,咱们想什么状况下会产生一个0?code
诶,一个数乘以 10,在末尾就会多出一个 0。而 10 = 5 * 2。class
一组数相乘的结果末尾有几个0,取决于这组数因式分解后有几对 5 和 2 的因子。效率
针对于 n! 这个题目,有这样一个事实:把相乘的数因式分解后,2 的个数确定大于 5 的个数。循环
因此,这个问题能够拆解为:只要求出因式分解后有几个 5 的因子便可,5的个数便是末尾出现的0的个数。计算机
这种解法的思路是:直接将 n! 中的每一个数,按照 5 来因式分解,最后把出现的 5 的个数加起来。时间
public int calculateZeroInFactorial(int n) { int count = 0; // 循环判断全部的乘数 for (int i = n; i > 0; i++) { if (i % 5 == 0) { // 若是这个乘数能够对 5 进行因式分解,再看这个乘数能够分解出几个5 int a = i; while(a % 5 == 0) { a = a / 5; count++; } } } return count; }
可是这种算法的时间复杂度为 O(nlog(n)),那有没有更快的算法呢?while
分析:co
因此,n! 的结果能够拆分为多少个 5 因子呢?
n/5 + n/25 + n /125 + n/625 + ….
好比 128!的阶乘的结果末尾有几个0呢?
128/5 +128/25 + 128/125 = 25+5+1 = 31 个
又如:1247! 的阶乘的结果末尾有几个0呢?
1247/5 + 1247/25 + 1247/125 + 1247/625 = 249+49+9+1 = 308 个
public int calculateZeroInLogN(int n) { int count = 0; while (n > 0) { count += n / 5; n /= 5; } return count; }
这种算法的时间复杂度为 O(log(n)),效率会高不少,并且仅需几行代码。