Python 如何改进euler 14的代码?
我解决了,但我使用的程序非常慢。我看了看其他人做了什么,他们都提出了优雅的解决方案。我试图理解他们的代码,但没有成功 这是我的代码(用于确定Collatz链长度的函数Python 如何改进euler 14的代码?,python,Python,我解决了,但我使用的程序非常慢。我看了看其他人做了什么,他们都提出了优雅的解决方案。我试图理解他们的代码,但没有成功 这是我的代码(用于确定Collatz链长度的函数 def collatz(n): a=1 while n!=1: if n%2==0: n=n/2 else: n=3*n+1 a+=1 return a 然后我使用了蛮力。它很慢,我知道它很弱。有人能告诉我为什么我的代码很弱,以及我如何用简单的英语改进我的代码吗。 请记住,
def collatz(n):
a=1
while n!=1:
if n%2==0:
n=n/2
else:
n=3*n+1
a+=1
return a
然后我使用了蛮力。它很慢,我知道它很弱。有人能告诉我为什么我的代码很弱,以及我如何用简单的英语改进我的代码吗。
请记住,我是一名初学者,我的编程技能是基本的。与其从头到尾计算每个可能的链,不如保留链起点及其结果长度的缓存。例如
13 40 20 10 5 16 8 4 2 1
你可以记住以下几点:
chain_sizes = {}
chain_sizes[13] = 10
chain_sizes[40] = 9
chain_sizes[40] # => 9
20 in chain_sizes # => False
现在,您只需调整算法以使用此字典(用值填充它并查找中间数字)
顺便说一句,这可以用递归很好地表达。这里可能出现的链大小不会溢出堆栈:)简单地说,因为我的英语很糟糕;-) 可以一次计算几个连续的迭代 以k
0
位结尾的数字的第k次迭代:
C^k(a*2^k) = a
C^(2k)(a*2^k + 2^k - 1) = a*3^k + 3^k - 1 = (a + 1)*3^k - 1
以k1
位结尾的数字的第(2k)次迭代:
C^k(a*2^k) = a
C^(2k)(a*2^k + 2^k - 1) = a*3^k + 3^k - 1 = (a + 1)*3^k - 1
比照公式;另请参见我的Python包中的(法语)和模块
将以下代码与Niklas B解释的记忆技术相结合:
#!/usr/bin/env python
# -*- coding: latin-1 -*-
from __future__ import division # Python 3 style in Python 2
from __future__ import print_function # Python 3 style in Python 2
def C(n):
"""Pre: n: int >= 1
Result: int >= 1"""
return (n//2 if n%2 == 0
else n*3 + 1)
def Ck(n, k):
"""Pre: n: int >= 1
k: int >= 0
Result: int >= 1"""
while k > 0:
while (n%2 == 0) and k: # n even
n //= 2
k -= 1
if (n == 1) and k:
n = 4
k -= 1
else:
nb = 0
while (n > 1) and n%2 and (k > 1): # n odd != 1
n //= 2
nb += 1
k -= 2
if n%2 and (k == 1):
n = (n + 1)*(3**(nb + 1)) - 2
k -= 1
elif nb:
n = (n + 1)*(3**nb) - 1
return n
def C_length(n):
"""Pre: n: int >= 1
Result: int >= 1"""
l = 1
while n > 1:
while (n > 1) and (n%2 == 0): # n even
n //= 2
l += 1
nb = 0
while (n > 1) and n%2: # n odd != 1
n //= 2
nb += 1
l += 2
if nb:
n = (n + 1)*(3**nb) - 1
return l
if __name__ == '__main__':
for n in range(1, 51):
print(n, ': length =', C_length(n))
当你在Project Euler上解决一项任务时(即使代码效率很低),你也可以下载一份pdf文档,解释如何最有效地解决该任务。正如你所知,到目前为止,你已经问了六个问题,其中许多问题都有很好的答案。“接受”一个能解决你问题的答案是很好的礼仪。您可以通过单击最佳答案下方的复选标记来完成此操作。你应该回去为你的旧答案做这件事;我相信帮助过你的人会很感激的。非常感谢我重新编写了我的程序,现在需要11.1秒。我想它仍然可以改进,但相比85秒,waw。我真得绞尽脑汁想办法,但现在没事了。Niklas B你太棒了。