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