Project Euler#20的算法速度慢

时间:2012-07-20 19:22:55

标签: performance lua

以下是我要解决的问题:http://projecteuler.net/problem=20(找到100中的数字之和!)

我正在使用Lua,它只有double作为数字类型,所以我不得不手动接近它。我使用的代码几乎与我用于问题16的代码相同,它类似(找到2 ^ 1000中的数字之和)。然而,这次问题似乎超出了我的算法,在相当长的时间内解决 - 它达到了大约32!在我需要等待超过10秒才能计算下一个总数之前,我需要等待34个!它比我等待的时间更长。有什么方法可以加快速度(使用'原始'Lua - 而不是LuaJIT或类似的东西)?

local sum = {1}
for i=1,100 do
    local carry = 0
    for v=1,#sum do
        local c = carry
        carry = 0
        local t = sum[v] * i
        while t >= 10 do
            t = t - 10
            carry = carry + 1
        end
        local s = t + c
        while s >= 10 do
            s = s - 10
            carry = carry + 1
        end
        sum[v] = s
    end
    if carry > 0 then
        sum[#sum+1] = carry
    end
    print(""..i.."! = "..getCharactersReversed(sum))
end

2 个答案:

答案 0 :(得分:5)

您的问题是(n+1)!的十进制表示长度可能比n!的长度多一个。第一次发生在n == 14

14! =   87178291200
15! = 1307674368000

因此,您的最终carry为13,领先的“数字”大于10.从那时起,该问题变得越来越糟,打印出#sum并且最终产生收益率

15      11      13
16      12      20
17      13      35
18      14      64
19      15      121
20      16      243
21      17      510
22      18      1124
23      19      2585
24      20      6204
25      21      15511
26      22      40329
27      23      108888
28      24      304888
29      25      884176
30      26      2652528
31      27      8222838
32      28      26313083

通过逐步减法将leading_number * i减少到小于10的数字需要越来越长。在某些时候(估计大约45),该值变得如此之大以至于t - 10 == t并且您陷入无限循环。 LuaJIT根本没有帮助。

所以你必须确保你永远不会写一个大于9的数字,例如通过减少前一个数字的循环中的最后一个进位并根据需要添加多个数字。这样做,程序运行没有明显的延迟。

if carry > 0 then
    local w = #sum+1
    local cc = 0
    while carry > 0 do
        while carry >= 10 do
            carry = carry - 10
            cc = cc + 1
        end
        sum[w] = carry
        w = w+1
        carry = cc
        cc = 0
    end
end

但是确定数字和除法进位更加简洁,对于更大的因子也更有效率(当将数字乘以100时,结果平均为450,需要45次减法,但是两次除法就足够了因为所有因素)。

答案 1 :(得分:0)

试试这段简短的代码:

    def factorial(n):
        return reduce(lambda x,y: x*y,[_ for _ in range(1,n+1)])

    print sum(map(int,list(str(factorial(100)))))