求N阶乘末尾0的个数

2022年6月25日,面试压轴题,自己毫无思路,在面试官提示下仍无思路。
现整理并记录,以鞭策自己,知耻而后勇。

1、逻辑推导

n ! = 1 × 2 × 3 × . . . × n = 1 × 2 × 3 × ( 2 × 2 ) × 5 × ( 2 × 3 ) × . . . × n = 1 × 2 a × 3 b × 5 c × 7 d × 1 1 e . . . n! = 1 \times 2\times3\times...\times n\\ \quad=1\times2\times3\times(2\times2)\times5\times(2\times3)\times...\times n\\ \quad= 1 \times 2^a\times3^b\times5^c\times7^d\times11^e... n!=1×2×3×...×n=1×2×3×(2×2)×5×(2×3)×...×n=1×2a×3b×5c×7d×11e...

n! 可以表达为素数指数的乘积(任何整数都可以这样表示)。
因此,n! 末尾0的个数为 min(a, c),通过简单归纳,易知 a>c永远成立,即min(a, c) = c,求得c(质因子5的个数),即为问题答案。
5, 10, 15, 20, 25, 30,…等数字,可以由素数5与其他素数相乘得到,因此可以有如下推导。

f ( n ) = c = [ l o g 5 5 ] + ( [ l o g 5 5 ] + [ l o g 5 2 ] ) + ( [ l o g 5 5 ] + [ l o g 5 3 ] ) + . . . + [ l o g 5 25 ] + ( [ l o g 5 5 ] + [ l o g 5 2 ] + [ l o g 5 3 ] ) + . . . = l o g 5 5 + l o g 5 5 + l o g 5 5 + l o g 5 5 + l o g 5 25 + l o g 5 5 + . . . + l o g 5 125 + . . . ( 式 1 ) = 1 + 1 + 1 + 1 + 2 + 1 + . . . + 1 + 3 + 1 + . . . + 1 + 4... = [ n / 5 ] + [ n / 5 / 5 ] + . . . = ∑ i = 1 ∞ [ n / 5 i ] ( 式 2 ) f(n)=c\\ \quad= [log_55]+( [log_55]+[log_52])+([log_55]+[log_53])+ ...+ [log_525]+([log_55]+[log_52]+[log_53])+...\\ \quad= log_55+ log_55+ log_55+ log_55+ log_525+ log_55+...+ log_5125+... \quad\quad\quad (式1)\\ \quad = 1 + 1+1+1+2+1+...+1+3+1+...+1+4...\\ \quad=[n/5] + [n/5/5] + ...\\ \quad=\sum \limits _{i = 1}^{\infty}[{n/5^i}]\quad\quad\quad\quad \quad\quad\quad\quad \quad\quad\quad\quad \quad\quad\quad\quad \quad\quad\quad\quad \quad\quad\quad \quad\quad\quad \quad (式2) f(n)=c=[log55]+([log55]+[log52])+([log55]+[log53])+...+[log525]+([log55]+[log52]+[log53])+...=log55+log55+log55+log55+log525+log55+...+log5125+...(1)=1+1+1+1+2+1+...+1+3+1+...+1+4...=[n/5]+[n/5/5]+...=i=1[n/5i](2)

[]为取整符号

2、代码实现

2.1 推导式1的代码实现

# 实现1
def zero_count(n):
	cnt = 0
	for i in range(1, n+1):
		while i % 5 == 0:  # 此处不能用i // 5 > 0的条件,例如30会被累计2次(30, 6都满足)
			cnt += 1
			i //= 5  # i = i // 5
	return cnt
print(zero_count(26))  # result is 6

# 实现2
def zero_count(n):
	cnt = 0
	for i in range(5, n+1, 5):  # [5, 10, 15...]
		while i % 5 == 0:
			cnt += 1
			i //= 5  # i = i // 5
	return cnt
print(zero_count(10000000))  # result is 2499999

时间复杂度为 O ( N ) O(N) O(N)

2.2 推导式2的代码实现

def zero_count(n):
	cnt = 0
	while n // 5 > 0:
		cnt += n // 5
		n //= 5  # 可以简化为 n //= 5; cnt += n
	return cnt
print(zero_count(10000000000000000)) # result is 2499999999999996

此种方式,时间复杂度为 O ( L o g 5 N ) O(Log_5N) O(Log5N),即 O ( L o g N ) O(LogN) O(LogN)

整理数学表达式及代码实现,耗费了不少时间,确实暴露了基础的薄弱,编程分析思考能力的欠缺,后续应不断努力训练加强。知耻而后勇。

3、参考资料

2022.7.10 v1.0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值