项目欧拉 - 问题160

时间:2010-06-29 12:21:47

标签: python math optimization

  

对于任何N,让f(N)为最后五位   尾随零之前的数字   ñ!例如,

9!  = 362880 so f(9)=36288 
10! = 3628800 so f(10)=36288 
20! = 2432902008176640000 so f(20)=17664
     

查找f(1,000,000,000,000)

我已成功解决了这个问题,我的函数可以正确找到f(9),f(10)等等。但是它会遇到更大的数字,特别是问题要求的数字 - f(10 ^ 12)。

我目前的优化如下:我从乘数和总和中删除尾随零,并在每次乘法后将总和缩短为5位数。 python中的代码如下:

def SFTR (n):
 sum, a = 1, 2
 while a < n+1:
  mul  = int(re.sub("0+$","",str(a)))
  sum *= mul
  sum  = int(re.sub("0+$","",str(sum))[-5:])
  a   += 1
 return sum 

任何人都可以告诉我为什么这个功能在如此大规模扩展,以及为什么它需要这么长时间。此外,如果有人可以提示我正确的方向来优化我的算法。 (一般主题的名称就足够了)谢谢。

更新

我已经对优化进行了一些更改,但速度明显更快,但对于f(10 ^ 12)来说仍然不够快。谁能告诉我什么时候我的代码变慢或者如何让它更快?

def SFTR (n):
    sum, a = 1, 2
    while a < n+1:
        mul  = a

        while(mul % 10 == 0): mul = mul/10
        mul  = mul % 100000

        sum *= mul

        while(sum % 10 == 0): sum = sum/10
        sum  = sum % 100000

        a   += 1
    return sum

3 个答案:

答案 0 :(得分:7)

mul会变得非常大。这有必要吗?如果我要求你计算最后5个非零数字1278348572934847283948561278387487189900038 * 38758 手工,你确实需要知道第一个数字到底有多少位数?

答案 1 :(得分:2)

经常构建字符串很昂贵。截断到最后五位时,我宁愿使用模运算符。

python -m timeit 'x = str(111111111111111111111111111111111)[-5:]'
1000000 loops, best of 3: 1.09 usec per loop
python -m timeit 'x = 111111111111111111111111111111111 % 100000'
1000000 loops, best of 3: 0.277 usec per loop

同样适用于剥离尾随零。应该有一种更有效的方法来做到这一点,你可能不必每一步都这样做。

我没有检查你的算法的正确性,但这只是一个优化提示。

答案 2 :(得分:1)

实际上,您甚至可能注意到只有一组受限的可能的尾随非零数字。如果我没记错的话,当你只查看最后5位时,只有几千种可能的尾随非零数字组合。例如,最终的非零数字是否有可能是奇数? (忽略0!和1的特殊情况!这里。)