分析:这道题的思路相对比较直接,最重要的优化技巧是要把已经计算过链条长度的数字缓存下来,从而加快计算之后数字链条长度的速度。题目中已经给出了若干数字,它们的链条长度是已知的,我们可以将其保存一个字典,字典的键为数字,对应的值为链条长度,例如169, 363601, 1454的链条长度都为三。
对每一个数字\(N\),我们建立一个数组\(arr\)保存其阶乘链条中的数。如果一个数\(a\)在上面的字典中已经出现了,则我们不需要再计算下去,直接用数组的长度加上数字\(a\)的链条长度即可。否则,我们检查数\(a\)是否在数组\(arr\)中已经出现过,如果已经出现过,则也可以停止计算,返回数组\(arr\)的长度即为数字\(N\)的的链条长度。如果以上两个条件都不满足,则我们计算数字\(a\)的各位数阶乘之和\(b\),并把\(b\)添加到数组\(arr\)中,继续循环。最后,我们在字典中添加数字\(N\)的链条长度。
另外一个优化技巧是,为了让我们在计算不同数字的链条长度可以共享同一个缓存字典,我们把这个字典设为全局变量,并在计算链条长度的函数中使用global关键字,使其可以修改字典这个全局变量,这样可以大大提高算法的效率。代码如下:
# time cost = 487 ms ± 2.44 ms
DT = {169:3,363601:3,1454:3,871:2,45361:2,872:2,45362:2,69:5,78:4,540:2}
def digit_fact_sum(x):
fac = [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
res = sum([fac[int(i)] for i in str(x)])
return res
def chain_length(n):
arr,m = [],n
global DT
while True:
if n in DT:
length = len(arr) + DT[n]
break
elif n in arr:
length = len(arr)
break
else:
arr.append(n)
n = digit_fact_sum(n)
DT[m] = length
return length
def main(N=10**6):
c = 0
for i in range(1,N):
if chain_length(i) == 60:
c += 1
return c