我使用以下代码来解决Project Euler问题14.对于那些不知道这个问题的人,我必须找到数量低于一百万且其Collatz序列中“步数”最多的数字。
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)
这在大约1分20秒内给出了正确的答案。但是我想我可以通过以下方式加快速度。首先,我指示程序记住每个值i的collatz序列中的步数。然后,如果在找到数字k的序列的过程中,我登陆前一个数字i我已经计算了序列,我只是将i的序列中的项数加到我计算的数字上到目前为止,对于k。
例如,假设我正在尝试计算13序列中的步数。前3个步骤是13-40-20-10。现在我已经计算出序列中10的步数为6(10-5-16-8-4-2-1)。因此,13的序列中的步骤数是3到10加到需要从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 outprinted到终端屏幕。当我尝试使用较小的值(即高达10000)时,我会得到与原始代码相同的答案,但速度要慢得多(即需要7秒而不是1秒)。
为什么会这样?
答案 0 :(得分:1)
优化的想法很好,但是你选择了错误的数据结构。
nterms = []
used = []
这两个列表用于存储您已经计算过的Collatz序列,对吧?但是要在列表中查找元素,时间复杂度为O(n),这是不够有效的。
相反,尝试使用字典,数字是键,以及它们的Collatz序列数作为值。例如,键10
的值为6
。
答案 1 :(得分:1)
检查是否可以从k
找到used
会减慢计算速度,因为检查是否可以从列表中找到元素具有 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%。
答案 2 :(得分:0)
查找列表中的元素是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秒。