繁体   English   中英

Python、ProjectEuler、优化使代码变慢

[英]Python, ProjectEuler, Optimization makes code slower

我使用下面的代码来解决 Project Euler 问题 14。对于那些不知道这个问题的人,我必须在它的 Collat​​z 序列中找到低于 100 万且“步骤”数最多的数字。

largen = 0

for i in range (1, 1000000):
    n = 0
    k = i
    while k != 1:

        if k % 2 == 0:
            k = k/2
            n = n+1


        else:
            k = 3*k+1
            n = n+1

    if n > largen:
        largen = n
        answer = i


print "Value with highest number of terms in collatz sequence is %d which has %d terms in its collatz sequence." % (answer, largen)

这给了我大约 1m20s 的正确答案。 但是我认为我可以通过以下方式加快速度。 首先,我指示程序记住每个值 i 在 collat​​z 序列中的步骤数。 然后,如果在查找数字 k 的序列的过程中,我遇到了我计算过的序列的前一个数字,我只需将序列中的项数添加到我计算的数字中到目前为止,k。

例如,假设我正在尝试计算序列中 13 的步数。前 3 步是 13-40-20-10。 现在我已经计算出 10 的序列中的步数是 6 (10-5-16-8-4-2-1)。 因此,13 的序列中的步数是达到 10 所需的 3 次加上从 10 达到 1 所需的 6 步,即总共 9 步。

为此,我将代码修改如下:

nterms = [] # for each value i, contains number of terms in collatz sequence
used = [] # list of used values of i (so can add nterms[i-1] to collatz sequence which redirects to i)

largen = 0

for i in range (1, 1000000):

    n = 0
    k = i
    while k != 1:

        if k in used:
            n = n+nterms[k-1]
            break

        elif k % 2 == 0:
            k = k/2
            n = n+1

        else:
            k = 3*k+1
            n = n+1

    if n > largen:
        largen = n
        answer = i

    used.append(i)
    nterms.append(n)

print "Value with highest number of terms in collatz sequence is %d which has %d terms in its collatz sequence." % (answer, largen)

但是,当我尝试运行它时,我将 MemoryError 打印到终端屏幕上。 当我尝试使用较小的值(即高达 10000)时,我得到与原始代码相同的答案,但速度要慢得多(即需要 7 秒而不是 1 秒)。

为什么会这样?

优化的想法是好的,但是你选择了错误的数据结构。

nterms = []
used = []

这两个列表是用来存放你已经计算好的Collat​​z序列的吧? 但是要在列表中查找元素,时间复杂度为 O(n),效率不够高。


相反,尝试使用字典,数字是键,它们的 Collat​​z 序列数作为值。 例如,键10的值为6

检查是否可以从used中找到k会减慢计算速度,因为检查是否可以从列表中找到元素的时间复杂度为O(n)

除了使用两个列表,您只能使用一个最初有1000000元素的列表,这些元素都被初始化为-1 然后在每次迭代中,一旦您知道 Collat​​z 编号,您就将其更新为相应的索引,以便您以后可以使用它:

largen = 0
answer = 0
memo = [-1] * 1000000
for i in xrange(1, 1000000):
    n = 0
    k = i
    while k != 1:
        # Since k can grow from original need to check it's within bounds
        if k < 1000000 and memo[k] != -1:
            n += memo[k]
            break
        if k % 2 == 0:
            k /= 2
        else:
            k = 3 * k + 1

        n += 1

    memo[i] = n
    if n > largen:
        largen = n
        answer = i

与字典缓存相比,这种方法在我的机器上快了大约 10-15%。

查找列表中的元素是一个 O(n) 操作,对于大型列表,这可能会变得非常慢。 另一方面,字典保证了恒定的查找时间复杂度(O(1)):

cache = {}

for i in range (1, 1000000):
    n = 0
    k = i
    while k != 1:

        if k in cache:
            n = n + cache[k]
            break

        if k % 2 == 0:
            k = k/2
            n = n+1


        else:
            k = 3*k+1
            n = n+1


    cache[i] = n
    if n > largen:
        largen = n
        answer = i


print "Value with highest number of terms in collatz sequence is %d which has %d terms in its collatz sequence." % (answer, largen)

在我的机器上,这种方法将解决方案的速度提高了大约 13 倍,从 OP 的约 26 秒到本答案中提出的约 2 秒。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM