【问题标题】:Project Euler p14 enhance performanceProject Euler p14 提升性能
【发布时间】:2013-10-19 18:27:04
【问题描述】:

我已经使用以下代码完成了项目欧拉问题 14:

def longest_Collatz_sequence():
    """
    returns longest Collatz
    sequence based on formula:
    n --> n/2 (n is even)
    n --> 3n + 1 (n is odd)
    """
    bestSequence = []
    lengthOfLongest = 0
    longestSequence = []
    for n in range(999999,1,-1):
        while n != 1:
            l = len(longestSequence)
            if n % 2 == 0:
                longestSequence.append(n)
                n /= 2
            elif n % 2 != 0:
                longestSequence.append(n)
                n = (n * 3) + 1
            if longestSequence[-1] == 2 and lengthOfLongest < l:  
                lengthOfLongest = l
                bestSequence = longestSequence[:]
                bestSequence.append(1)       
        longestSequence = []
    return bestSequence[0] 

获得最长的 Collat​​z 大约需要 39 秒 从 1000000 到 2 的数字序列。 我想知道我是否可以缓存任何值来加速我的代码,以及如何 从我的代码中删除 iflongestSequence[-1] == 2 而不会出现无限循环以及可以改进代码的任何其他方式。

为正整数集合定义以下迭代序列:

n → n/2(n 为偶数) n → 3n + 1(n 为奇数)

使用上面的规则并从 13 开始,我们生成以下序列:

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 可以看出,这个序列(从 13 开始,到 1 结束)包含 10 个术语。虽然还没有被证明(Collat​​z Problem),但人们认为所有的起始数字都以 1 结束。

100 万以下的哪个起始数字产生最长的链?

注意:一旦链启动,条款允许超过一百万。

【问题讨论】:

  • 您要做的第一件事是将 Collat​​z 序列长度逻辑分离到它自己的函数中。那么缓存起来会更容易。
  • @fritzone 每当我 google 以了解任何 Euler 项目中使用的算法时,我都会被 Project Euler 解决方案轰炸,所以除非 Euler 不了解 google 或如何使用任何搜索引擎,否则我真的看不出我的问题,在一大堆其他人中,对其他人做这个问题有什么影响。
  • @fritzone Project Euler 问题与家庭作业问题一样是该站点的主题。遇到这个问题的人不会被宠坏,因为 1) 不看答案真的很容易,2) 由于 Project Euler 是一个“家庭作业”问题,答案往往只是部分完整。
  • @WaleedKhan 你的意思是,把 n --> n/2 (n 是偶数) n --> 3n + 1 (n 是奇数)放在它自己的一个函数中并缓存结果那个?对不起,我很缺乏经验,所以有时我需要一点才能完全理解
  • 我的意思是说你的main函数应该和print(max(collatz(i) for i in range(1000000)))一样简单。然后您应该设计collatz(n),以便它返回n 的Collat​​z 序列长度。然后你可以在collatz的工作中添加memoization。

标签: python performance algorithm


【解决方案1】:

每次您在序列中生成一个项目时,您也在为 那个 项目生成项目。例如,对于 13,您会发现它产生 10 个项目。但是在这个过程中你也会发现 40 产生 9 个项目,20 产生 8 个项目,10 产生 7 个项目,等等。你可以在列表或字典中记住这些信息,这样在做 13 之后,你就不必再看 40 、20、10、5、16、4 或 2。

此外,当您生成一个从未见过的序列时,您可以查看此信息并将其用作快捷方式。对于 13,您在看到 13 之前已经看到了 10,因此您只需计算 40、20、10,然后您知道 10 产生 7 个项目,因此您只需将其添加到您已经看到的 3 中,而无需费心计算休息。

这将使用相当多的内存,但对于您必须考虑的项目数量来说它是完全可行的。您可以设置某种截断(例如,仅存储 100,000 或以下数字的结果),这仍然可以大大提高速度但使用更少的内存。

一个简单的方法是重写你的函数来递归而不是迭代地计算序列,然后应用一个记忆装饰器,比如this one。递归有一些开销,但记忆化的好处可能会超过这个。

【讨论】:

  • 谢谢,不久前我在上 MIT 6.00x python 课程时做了一些记忆,但对于如何将它与函数一起使用仍然有点模糊,但我会尝试你的建议看看哪个效果最好。
猜你喜欢
  • 2010-09-27
  • 1970-01-01
  • 1970-01-01
  • 2012-04-03
  • 2023-03-21
  • 2011-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多