题目描述
【leetcode】172. 阶乘后的零( Factorial Trailing Zeroes )
给定一个整数 n,返回 n! 结果尾数中零的数量。
说明: 你算法的时间复杂度应为 O(log n) 。

错误的思路1:
n!展开过程中,每次相乘时,尾数0的数量只与最后一位非0值有关,
所以每次相乘后累加末尾0的个数,然后只取最靠右的非0值。
这种想法是错的,反例 25*4=100,有2个0,若只考虑最靠右非0值,只能得到1个0
错误的思路2:
末尾0的数量即为1,2,3,…,n中因子5的个数,而因子5的个数即为下列数列和:
i
n
t
(
n
/
5
)
,
i
n
t
(
n
/
5
2
)
,
.
.
.
,
i
n
t
(
n
/
5
n
u
m
)
int(n/5),int(n/5^2),...,int(n/5^{num})
int(n/5),int(n/52),...,int(n/5num) 。其中项数
n
u
m
=
i
n
t
(
l
g
(
n
)
/
l
g
(
5
)
)
num = int(lg(n)/lg(5))
num=int(lg(n)/lg(5)) ;
上面的数列似乎是等比数列前n项和的形式,但是请注意,其中每一项都带了int(),即向下取整,所以把它当作等比数列的画会引入误差积累,计算到某些输入值会出错,但是还是想讨论一下。
若不考虑int()带来的误差,则
S
n
=
a
1
(
1
−
q
n
)
/
(
1
−
q
)
Sn = a_1(1-q^n)/(1-q)
Sn=a1(1−qn)/(1−q) ;,注意,由上面推导,Sn必定是整数,例如Sn=49。由于q=1/5为浮点数,导致Sn计算将导致误差,Sn可能为48.999,或者是49.0001。所以我们需要把Sn式子分子分母同乘以q^n,变形为无浮点数的运算,
S
n
=
a
1
(
5
n
−
1
)
/
(
4
∗
5
n
−
1
)
Sn = a_1(5^n-1)/(4*5^{n-1})
Sn=a1(5n−1)/(4∗5n−1) ;
错误的思路2的代码:
#include <cmath>
class Solution {
public:
int trailingZeroes(int n) {
if(0 == n)
return 0;
int num = log(n)/log(5);
int a1 = n/5;
// double q = 1/5.0;
// int count = a1*(1-1/pow(5,num))/(1-q) ;
int count = a1*(pow(5,num)-1)/(4*pow(5,num-1));
return count;
};
第一次解答
思路:
阶乘n!中末尾0的数量 等于 阶乘n!中因子10的数量 进而等于 阶乘中因子2和因子5的成对出现的次数,因为因子2需要每递增2就至少新增一个,而因子5需要每递增5才至少出现一个,所以2的数量远比5的数量多,因此,又有
阶乘n!中末尾0的数量 等于 阶乘n!中因子5的数量
到这里已经可以直接求解,但是若是遍历1-n去寻找所有因子5,时间复杂度为nlogn,能否有更简单的方法?答案当然是有。
通过观察可得出,阶乘n!中因子5的数量 即为下列数列和:
i
n
t
(
n
/
5
)
,
i
n
t
(
n
/
5
2
)
,
.
.
.
,
i
n
t
(
n
/
5
n
u
m
)
int(n/5),int(n/5^2),...,int(n/5^{num})
int(n/5),int(n/52),...,int(n/5num)
其中,项数
n
u
m
=
i
n
t
(
l
o
g
5
(
n
)
)
num = int(log_5(n))
num=int(log5(n)) 。请注意,其中每一项都带了int(),即向下取整,所以把它当作等比数列的画会引入误差积累,所以我们不能直接利用等比数列前n项和计算结果,需要用程序展开计算每一项,时间复杂度为
l
o
g
5
(
n
)
log_5(n)
log5(n)即O(log n)。
test case:
5
0
1
200
class Solution {
public:
int trailingZeroes(int n) {
int count = 0;
while(n>4){
n = n/5;
count += n;
}
return count;
}
};
结果:

本文深入解析LeetCode 172题——阶乘后的零,探讨正确与错误的算法思路,揭示阶乘尾零数量的计算原理,并提供高效的O(logn)算法实现。
296

被折叠的 条评论
为什么被折叠?



