一、题目描述
给定一个整数 n ,返回 n! 结果中 尾随零的数量。
阶乘定义:
n! = n × (n-1) × (n-2) × ... × 3 × 2 × 1
示例
示例 1
输入:n = 3
输出:0
解释:3! = 6,没有尾随 0
示例 2
输入:n = 5
输出:1
解释:5! = 120,有 1 个尾随 0
示例 3
输入:n = 0
输出:0
数据范围
0 <= n <= 10^4
进阶要求:设计 O(log n) 时间复杂度的算法。
二、问题关键
尾随 0 的来源是 10。
而:
10 = 2 × 5
也就是说:
只要有一对 (2,5) 就会产生一个 0
例如:
2 × 5 = 10 → 产生一个 0
三、为什么只需要统计 5?
在 n! 中:
-
偶数很多 → 2 的因子很多
-
5 的因子比较少
例如:
10! = 3628800
里面:
2 的数量 >> 5 的数量
因此:
尾随 0 的数量 = 5 的因子数量
四、需要注意的特殊情况
某些数提供 多个 5。
例如:
25 = 5 × 5
125 = 5 × 5 × 5
所以计算公式为:
n/5 + n/25 + n/125 + ...
直到为 0。
五、图解理解
以 n = 25 为例:
第一次统计
25 / 5 = 5
说明:
5,10,15,20,25
共 5 个 5
第二次统计
25 / 25 = 1
说明:
25 = 5 × 5
多贡献 1 个 5
总数
5 + 1 = 6
因此:
25! 尾随 0 = 6
六、解法一:数学规律(推荐)
核心思路:
不断除以 5。
n/5
n/25
n/125
...
时间复杂度:
O(log₅ n)
C语言实现
int trailingZeroes(int n) {
int count = 0;
while (n > 0) {
n /= 5;
count += n;
}
return count;
}
七、解法二:for循环写法
逻辑完全相同,只是写法不同。
C语言实现
int trailingZeroes(int n) {
int count = 0;
for (long long i = 5; i <= n; i *= 5) {
count += n / i;
}
return count;
}
过程示例(n=100)
100/5 = 20
100/25 = 4
100/125 = 0
结果:
20 + 4 = 24
八、错误解法(不推荐)
有些人会真的去计算:
n!
例如:
5! = 120
10! = 3628800
然后统计末尾 0。
这种方法问题:
1️⃣ 阶乘非常大
20! 就已经超过 long long
2️⃣ 时间复杂度高
因此不推荐。
九、复杂度分析
| 方法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 数学统计 | O(log n) | O(1) |
| 暴力阶乘 | 极高 | 极高 |
十、总结
核心思想只有一句话:
阶乘尾零 = 统计所有因子5的数量
计算公式:
n/5 + n/25 + n/125 + ...
最终实现只需 几行代码 ,时间复杂度 O(log n)。