[英]Python, ProjectEuler, Optimization makes code slower
我使用下面的代码来解决 Project Euler 问题 14。对于那些不知道这个问题的人,我必须在它的 Collatz 序列中找到低于 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 在 collatz 序列中的步骤数。 然后,如果在查找数字 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 = []
这两个列表是用来存放你已经计算好的Collatz序列的吧? 但是要在列表中查找元素,时间复杂度为 O(n),效率不够高。
相反,尝试使用字典,数字是键,它们的 Collatz 序列数作为值。 例如,键10
的值为6
。
检查是否可以从used
中找到k
会减慢计算速度,因为检查是否可以从列表中找到元素的时间复杂度为O(n) 。
除了使用两个列表,您只能使用一个最初有1000000
元素的列表,这些元素都被初始化为-1
。 然后在每次迭代中,一旦您知道 Collatz 编号,您就将其更新为相应的索引,以便您以后可以使用它:
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.