项目Euler 14代码效率

时间:2015-04-08 11:51:16

标签: python performance

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编写。

  

最长的Collat​​z序列

     

问题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个术语。虽然尚未证实(Collat​​z问题),但据认为所有起始数字都以1结束。

     

哪个起始编号低于一百万,产生最长的链?

     

注意:链条启动后,条款允许超过一百万。

我写了部分因为它并没有真正输出解决方案,因为我无法在整个1 - 1000000范围内真正运行它。这太慢了 - 我最后一次杀死这个过程花了20多分钟。我几乎没有开始使用python和编程(大约2周),我希望了解我在效率方面犯的明显错误。我搜索了一些解决方案,甚至普通的解决方案都比我的快几个数量级。那我在这里错过了什么?是否有任何文献指南,以避免将来犯同样的错误?

5 个答案:

答案 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