l = [[i, i, 1] for i in range(1,1000000)]
def collatz(li):
for el in li:
if el[1] == 1:
li.remove(el)
elif el[1] % 2 == 0:
el[1] = el[1] / 2
el[2] += 1
elif el[1] % 2 == 1:
el[1] = 3*el[1] + 1
el[2] += 1
return li
while len(collatz(l)) >= 2:
l = collatz(l)
print l
嗨,这是Euler problem 14的(部分)解决方案,用Python编写。
最长的Collatz序列
问题14
为正整数集定义了以下迭代序列:
n → n/2 (n is even) n → 3n + 1 (n is odd)
使用上面的规则并从13开始,我们生成以下序列:
13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1
可以看出,该序列(从13开始,在1结束)包含10个术语。虽然尚未证实(Collatz问题),但据认为所有起始数字都以1结束。
哪个起始编号低于一百万,产生最长的链?
注意:链条启动后,条款允许超过一百万。
我写了部分因为它并没有真正输出解决方案,因为我无法在整个1 - 1000000范围内真正运行它。这太慢了 - 我最后一次杀死这个过程花了20多分钟。我几乎没有开始使用python和编程(大约2周),我希望了解我在效率方面犯的明显错误。我搜索了一些解决方案,甚至普通的解决方案都比我的快几个数量级。那我在这里错过了什么?是否有任何文献指南,以避免将来犯同样的错误?
答案 0 :(得分:1)
问题是你使用效率低下的强力算法。这是我对项目Euler的问题14的解决方案。运行需要几秒钟。关键是你应该将以前的结果保存在字典中,这样你就不必再次计算这些结果了。:
#problem 14 project euler
import time
start=time.time()
has2={}
def collatz(x):
seq=[]
seq.append(x)
temp=x
while(temp>1):
if temp%2==0:
temp=int(temp/2)
if temp in has2:
seq+=has2[temp]
break
else:
seq.append(temp)
else:
temp=3*temp+1
if temp in has2:
seq+=has2[temp]
break
else:
seq.append(temp)
has2[x]=seq
return len(seq)
num=0
greatest=0
for i in range(1000000):
c=collatz(i)
if num<c:
num=c
greatest=i
print('{0} has {1} elements. calculation time ={2} seconds.'.format(greatest,num,time.time()-start))
答案 1 :(得分:1)
对sara的回答有一点改进
import time
start = time.time()
def collatz(n):
k = n
length = 1
nList = []
nList.append(n)
while n != 1:
if n not in dic:
n = collatzRule(n)
nList.append(n)
length += 1
else:
# we dont need the values but we do need the real length for the for-loop
nList.extend([None for _ in range(dic[n] - 1)])
length = (length - 1) + dic[n]
break
for seq in nList:
if seq not in dic:
dic[seq] = len(nList) - nList.index(seq)
return length
def collatzRule(n):
if n % 2 == 0:
return n // 2
else:
return 3 * n + 1
longestLen = 0
longestNum = 0
dic = {}
for n in range(2, 1000001):
prsntLen = collatz(n)
if prsntLen > longestLen:
longestLen = prsntLen
longestNum = n
# print(f'{n}: {prsntLen}')
print(f'The starting num is: {longestNum} with the longest chain having: {longestLen} terms.')
print(f'time taken: {time.time() - start}')
答案 2 :(得分:0)
正如@Sara所说,您可以使用字典来保存以前的结果,然后查找它们以使程序运行得更快。但我不太了解你的结果,超过20分钟的声音听起来像你有一些问题。 通过使用暴力,我可以让代码在16秒左右运行。
#!/bin/python3
########################
# Collatz Conjecture #
# Written by jeb 2015 #
########################
import time
current = 0
high = 0
# While number is not one, either divide it by 2
# or multiply with 3 and add one
# Returns number of iterations
def NonRecursiveCollatz(i):
counter = 1
while i != 1:
counter = counter + 1
if i%2 == 0:
i = i / 2
else:
i = 3*i + 1
return counter
time_start = time.time()
# Test all numbers between 1 and 1.000.000
# If number returned is higher than last one, store it nd remember
# what number we used as input to the function
for i in range(1,1000000):
current = NonRecursiveCollatz(i)
if current > high:
high = current
number = i
elapsed_time = time.time() - time_start
print "Highest chain"
print high
print "From number "
print number
print "Time taken "
print elapsed_time
输出:
Highest chain
525
From number
837799
Time taken
16.730340004
答案 3 :(得分:0)
Sara的答案很棒,但可以提高效率。
如果我们从函数返回的值是def collatz(x):
count = 1
temp = x
while temp > 1:
if temp % 2 == 0:
temp = int(temp/2)
if temp in has2: # calculate temp and check if in cache
count += has2[temp]
break
else:
count += 1
else:
temp = 3*temp + 1
if temp in has2:
count += has2[temp]
break
else:
count += 1
has2[x] = count
return count
837799 has 525 elements. calculation time =1.97099995613 seconds.
,为什么不只计算迭代次数而不是先列出一个列表呢?
我稍微更改了代码,性能提升很明显
837799 has 525 elements. calculation time =11.3389999866 seconds.
与原始版本相比
int
使用/all_file/profil.php
列表而不是构建整个列表快80%。
答案 4 :(得分:0)
//Longest Colletz Sequence
public class Problem14 {
static long getLength(long numb) {
long length = 0;
for(long i=numb; i>=1;) {
length++;
if(i==1)
break;
if(i%2==0)
i = i/2;
else
i = (3*i)+1;
}
return length;
}
static void solution(long numb) {
long number = numb;
long maxLength = getLength(number);
for(long i=numb; i>=1; i--) {
if(getLength(i)>=maxLength) {
maxLength = getLength(i);
number = i;
}
}
System.out.println("`enter code here`Length of "+number+" is : "+maxLength);
}
public static void main(String args[]) {
long begin = System.currentTimeMillis();
solution(1000000);
long end = System.currentTimeMillis();
System.out.println("Time : "+(end-begin));
}
}
output :
Length of 837799 is : 525
Time : 502