项目欧拉#10

时间:2014-04-25 10:13:09

标签: python

我对算法非常陌生,几周前就开始编码了。请帮我解决这个问题:

低于10的素数之和为2 + 3 + 5 + 7 = 17.

找出200万以下所有素数的总和。

我尝试了通常的暴力方法,当然是糟透了。我试着阅读Sieve算法。并实现了这一点,是的,它仅针对奇数运行:

i=[x for x in range(3,2000001,2)]
print(len(i))
j=0
sum=2
while(max(i)!=j):
    m=0
    while(m<(2000000-(i[j]**2)/(2*i[j]))):
        a=(i[j]**2)+2*m*i[j] 
        if a in i:
            i.remove(a)
        m+=1
    j+=1
for s in range(1,len(i)+1):
    sum+=i[s]
print(sum)

该计划仍需要超过5个小时。我在3个小时内停了下来。我哪里错了?

4 个答案:

答案 0 :(得分:4)

看来你正在努力学习,所以我不会给你完整的解决方案,只是路径。

  • 不要混淆列表,将元素放入和取出,检查它们是否在等等。这是效率低下的一个因素。相反,请保留已知素数列表。
  • 写评论。我一直盯着你的代码几分钟,我不知道它的作用。
  • 适当时使用math个功能。 math.sqrt**0.5快(大约多30%)。
  • 此块: for s in range(1,len(i)+1): sum+=i[s] 伤害。您可以通过以下方式获取列表的总和:输入sum(i)
  • [x for x in range(3,2000001,2)]range(3,2000001,2)(在Python2中)或list(range(3,2000001,2))(在Python3中)完全相同。
  • 不要将变量名称用作iam。目前尚不清楚它们是什么。

你怎么知道一个数字是否是素数?对于它下面的所有素数,检查它们是否除以你的数字。如果没有,请保存。实际上,您只能检查小于数字平方根的素数。

如果你想换取内存以获得速度,你可以使用@vamosrafa的功能,然后sum(prime(2e6))。 (在Python2中,为range更改xrange。你只需要记忆来同时保存几个数字,但会做很多不必要的分割(如果它不能被3和5整除,它将不能被15整除)。

答案 1 :(得分:3)

筛子是一种很好的方法,但是您的实施很混乱,显然无法正常工作。考虑这个非常简单(未经优化)的实现:

def prime_sieve(max_):
    """Create a list containing all prime numbers equal to or less than max_."""
    primes = list(range(max_+1)) # all numbers 0 to max_
    primes[1] = 0 # 1 is not prime
    for number in primes: # iterate through all numbers
        if number: # if not 0 (i.e. prime)
            for multiple in range(2, (max_ // number) + 1):
                primes[number * multiple] = 0 # set multiples to zero
    return primes

可以提高效率,但max_ == 2000000可以在我的机器上运行大约两秒钟。

使用for循环通常比while循环更好地用于迭代列表之类的容器。另请注意,我将非素数留在列表中,但将它们设置为零 - 否则索引(代码中的i[j])将会中断。

对于测试示例:

>>> prime_sieve(10)
[0, 0, 2, 3, 0, 5, 0, 7, 0, 0, 0]
>>> list(filter(None, prime_sieve(10)))
[2, 3, 5, 7]
>>> sum(prime_sieve(10))
17

答案 2 :(得分:1)

我也被困在同一个地方,花了两个晚上出去解决这个问题。

然后,我拿起了标记朝圣者的DIVE INTO PYTHON,并且有一章关于生成器功能,我应用了这种技术来解决这个问题。这是生成器函数,它将解决这个问题:

def prime(max):

    for n in range(2,max):

        for x in range(2,int(n**0.5) + 1):

            if n%x == 0:


                break
        else:

            yield n

现在,写一个将调用它的另一个函数sum,无论是在shell还是在这个程序本身,我已经调用了shell的总和,但这将解决你的问题。

祝你好运! :)

答案 3 :(得分:0)

可以根据@jonrsharpe提供的代码进行一项改进 - 将for multiple in range(2, (max_//number)+1):替换为for multiple in range(number, (max_//number)+1):

def prime_sieve2(max_):
        primes = list(range(max_+1))
        primes[1] = 0 
        for number in primes:
                if number:
                        # starting from number rather than 2 
                        for multiple in range(number, (max_//number)+1): 
                                primes[number * multiple] = 0 
        return primes

之前的评估步骤(您可以跳过评估从2到数字^ 2 ):

check 2, 4, 6, 8, 10, 12, 14,...
check 3, 6, 9, 12, 15, 18, 21,...  (6 is already checked by '2')
check 5, 10, 15, 20, 25, 30, 35,...  (10, 15, 20 are already checked by '2' and '3')
check 7, 14, 21, 28, 35, 42, 49, 56,... (again, 14, 21, 28, 35, 42 are redundant checked)

增强后的评估步骤:

check 4, 6, 8, 10, 12, 14,...
check 9, 12, 15, 18, 21,...
check 25, 30, 35, ...
check 49, 56, ...