题目描述:

给定一个整数 ​​n​​​ ,返回 ​​n!​​ 结果尾数中零的数量。

示例 1:

输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。

示例 2:

输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零。

说明: 你算法的时间复杂度应为 O(log n)

题目分析:

    虽然这道题标着“简单”,但如果没有数学思维还真觉得不简单。显然,一看这道题你就会想到直接计算阶乘然后求末尾 ​​0​​ 的个数,但这种方法速度太慢了,甚至很容易溢出,所以在这里是行不通的。

    那就让我们分析一下,首先,末尾的 ​​0​​​ 如何而来,很容易想到,在九九乘法表中,有 ​​2 * 5 = 10​​​ 结果末尾有 ​​0​​​ 。所以,阶乘结果末尾有多少个 ​​0​​​ ,只要给当前的数乘以 ​​10​​​ 就可在结果末尾加一个 ​​0​​ 。

    看一个例子,对于 ​​5! = 5 * 4 * 3 * 2 * 1 = 120​​​ ,结果中末尾有一个 ​​0​​​ ,是因为式子中 ​​5 * 2 = 10​​​ 得来的,所以只要判断式子中有多少对 ​​5 和 2​​​ 即可得到结果末尾 ​​0​​​ 的个数。对于 ​​2​​​ 来说,每出现两个数总有一个是 ​​2​​​ 的倍数,而对于 ​​5​​​ 来说,每出现五个数才有一个是 ​​5​​​ 的倍数,是 ​​2 的倍数​​​ 的数总是比是 ​​5 的倍数​​​ 的数要多,所以我们直接找是 ​​5 的倍数​​​ 的数就行,例如找到 ​​10​​​ 个是 ​​5 的倍数​​​ 的数一定会找到超过 10 个是 ​​2 的倍数​​​ 的数,所以这 10 个 ​​5 的倍数​​​ 的数一定能找到足够多的 ​​2​​​ 与之相乘得到 ​​10​​​ 。因此通过 ​​n / 5​​​ 就可以计算出 ​​5​​​ 的个数。继续分析,我们会知道每隔 ​​25​​​ 个数出现了两个 ​​5​​​ ,因为 ​​5 * 5 = 25​​​ ,所以还要多算上一个 ​​5​​​ ,即加上 ​​n / 25​​​ 个 ​​5​​​ 。同理, ​​5 * 5 * 5 = 125​​​ ,出现了三个 ​​5​​​ ,我们还是一样要加上 ​​n / 125​​​ 个 ​​5​​​ ... 最后,应该使用 ​​n / 5 + n / 25 + n / 125 + ...​​​ 计算出现 ​​5​​​ 的个数。我们直接通过循环统计 ​​5​​​ 的个数就行,计算的时候先算 ​​n / 125​​​ 再通过 ​​n = n / 5​​​ 把 ​​n​​​ 更新,再计算 ​​n / 25​​ ,以防止溢出。

题解一:

执行用时: 1 ms

内存消耗: 35 MB

class Solution {
public int trailingZeroes(int n) {
// 统计末尾 0 的个数
int zeroCount = 0;
// 当 n 大于 0 循环除于 5 获得 5 的个数
while (n > 0) {
n /= 5;
// 累加计算 5 的个数
zeroCount += n;
}
return zeroCount;
}
}

题解二:

执行用时: 1 ms

内存消耗: 35.4 MB

class Solution {
// 递归求解法
public int trailingZeroes(int n) {
return n == 0? 0: n / 5 + trailingZeroes(n / 5);
}
}

题目来源:力扣(LeetCode)