(这是Project Euler Problem 14)
我试图通过使用Itertools来丰富我的Python技能。
我想从Python的itertools中的生成器获得设定迭代次数(1,000,000)的最大返回值索引。
这个功能有效,但是我无法弄清楚如何有效地获得最大值而不将其存储在一个庞大的一百万个长列表中,我认为这个列表很难有效。有智能的智能方式吗? (编辑:也许这是最简单的方法?)
当前代码是当链条达到100时它停止的那一刻是错误的。
#Project Euler Problem 14
#Which starting number, under one million, produces the longest chain?
import itertools
def length():
x=1
while True:
l=0
c=x #Create the running integer.
while c>1:
if c%2==0:
#Number is even, divide it by two.
c=c/2
l+=1
else:
#Number is odd, multiply by three and add one.
c=3*c+1
l+=1
yield l+1 #Add the final one as well and show the chain length.
x+=1 #Increment
print list(itertools.takewhile(lambda x:x<100,length()))
答案 0 :(得分:1)
我解决了以下问题:
import functools
def euler_014(max_=1000000):
longest = max_len = None
for n in range(1, max_):
length = len_collatz(n)
if max_len is None or length > max_len:
max_len, longest = length, n
return longest
def memoize(f):
cache = {}
@functools.wraps(f)
def func(*args):
if args not in cache:
cache[args] = f(*args)
return cache[args]
return func
@memoize
def len_collatz(n):
if n == 1:
return 1
if n % 2:
n = (n * 3) + 1
else:
n //= 2
return 1 + len_collatz(n)
此处memoize
通过存储len_collatz
的先前结果来提高效率,len_collatz
告诉您从n
到1
的序列长度(不实际上生成整个序列的列表)euler_014
只需要跟踪n
的最长长度和相关值。请注意,它不会保留所有结果 - 只是到目前为止最长系列的长度和产生该序列的n
的值。
答案 1 :(得分:1)
我看不出在这里使用itertools.take的原因。 Takewhile允许提前终止,但您不能提前终止,因为必须检查collatz(n)
以下每个n
一百万以下。
标准最大函数将在迭代中找到最高值。范围对象是在常量内存中工作的可迭代对象(即,它不使用范围中所有值的内部列表。)。我通常不会公开发布解决方案,但由于这只是前20个问题中的一个,并且已经发布了三个不同的解决方案...
def collatz(n):
return n // 2 if n%2 == 0 else 3*n + 1
def distance(n, cache={1:1}):
if n not in cache: cache[n] = distance(collatz(n)) + 1
return cache[n]
ans = max(range(1,1000000), key=distance)
print(ans)
你真的应该使用标准的最大功能。你不知道最长的链条有多长,所以第一个链条长于100不能保证工作。这只是猜测和检查。 Max发现时间最长而不将所有内容存储在内存中。
我应该留下一个我记得“距离”的免责声明。这意味着我的代码存储至少1,000,000个值,因此不需要重复计算collatz(n)。这需要花费几MB的RAM,但会将执行时间从一分钟缩短到几秒钟。这非常值得。
答案 2 :(得分:1)
使用不同的方法添加第二个答案;这个将使用生成器最小化内存占用量来生成collatz
序列。
然而,它要慢得多。运行这个需要大约60秒,相比之下memoize
d版本的第一次运行时为~5s(后续运行时为~1s,一旦cache
具有所有值),
def collatz(n):
while n > 1:
yield n
n = (n * 3) + 1 if n % 2 else n // 2
yield 1
def euler_014_iter(max_=1000000):
longest = max_len = None
for n in range(1, max_):
length = sum(1 for _ in collatz(n))
if max_len is None or length > max_len:
longest, max_len = n, length
return longest