最长的Collat​​z序列效率

时间:2015-03-22 15:34:58

标签: python

我正在尝试回答Problem 14 of Project Euler,不幸的是我的代码需要的时间超过运行所需的时间。我怎样才能使它高效,我减少了它但它仍然缺乏效率。我的代码在

之下
my_seq_final = []
for i in range(1000000, 0, -1):
    ans = i
    my_seq = [ans]
    while ans != 1:
        n = ans
        if n % 2 == 0:
            ans = n/2
        else:
            ans = 3*n + 1
        my_seq.append(ans)
    my_seq_final.append(my_seq)

tmp = 0
result = [0]
for j in my_seq_final[::-1]:
    if tmp < len(j):
        tmp = len(j)
        result[0] = j
    else:
        pass
print(result[0][0])

2 个答案:

答案 0 :(得分:2)

您可以使用memoization来避免多次计算相同的Collat​​z序列。

cache = {1: 1}
def collatz_count(n):
    if n not in cache:
        if n % 2 == 0:
            cache[n] = 1 + collatz_count(n / 2)
        else:
            cache[n] = 1 + collatz_count(3 * n + 1)
    return cache[n]

假设我用6:

调用此函数
 In []: collatz_count(6)
 Out[]: 9

这是序列[6, 3, 10, 5, 16, 8, 4, 2, 1]的长度。此外,缓存已被副作用修改:

 {1: 1, 2: 2, 3: 8, 4: 3, 5: 6, 6: 9, 8: 4, 10: 7, 16: 5}

此后,如果我用12调用函数,序列[12, 6, 3, 10, 5, 16, 8, 4, 2, 1]的长度(10)将非常快速地计算,因为第二项(6)已经与其长度相关联。

在您的问题中,大多数所需的长度将只是从缓存中检索或通过非常少的递归调用计算。

具体而言,在指定范围内,collatz_count的平均呼叫次数为:

  • 310.534203(不含缓存);
  • 3.16861(带缓存)。

PS:请注意,我选择将我的缓存实现为Python字典。生成的Collat​​z数确实远远超过10**6的给定界限(即,56,991,483,520是最大&#34;中间&#34;值)。这个大小的数组将为99.9961%为空,但仍需要至少~111 GB(每个值2个字节)。

答案 1 :(得分:0)

如果我正确阅读了代码,您将保存所有序列,最后决定哪个序列最长。

您可以确定地减少内存消耗,从而加快速度,只需确定当前序列的长度,然后将其与目前发现的最长序列进行比较。如果您需要打印它,那么您可以保存它。

您可以通过在数组中记录n的序列长度来加快速度。然后,当您尝试新的数字时,您可以检查该数字的长度是否已知,如果已知,只需将长度添加到当前序列长度即可。这使用内存,但记录整个序列的内存较少。