如何使埃拉托色尼筛法更快?

How to make the Sieve of Eratosthenes faster?

我正在尝试解决 Project Euler 中的第 10 个问题。它包括找到 200 万以下所有素数的总和。我根据埃拉托色尼筛法编写了以下代码。

import time
t0 = time.time()
n=200000
liste=list(range(2,n))
k=2
s=2
while k <=n:
    liste=list(set(liste)-set(range(k,n,k)))
    if liste!=[]:
        k=min(liste)
        s+=k
    else:
        break
print(s)
t1 = time.time()
total = t1-t0
print(total)

我针对n=200000 测试了上面的代码,但是对于n=2000000 来说太慢了。如果能得到任何改进此程序的帮助,我将不胜感激。

为了找到小于 200000 的素数之和,下面的代码(使用埃拉托色尼筛法)工作得更快,您的代码需要将近 55 秒,而下面的代码只需 0.8 秒即可执行!

import time
t0 = time.time()
n = 200000
sieve = [True] * (n + 1)
for i in range(2, n + 1) :
  if sieve[i] :
     for mult in range(i + i, n + 1, i) :
        sieve[mult] = False
s=0     
for i in range(2,n + 1):
    if sieve[i] :
        s+=i    
print(s)
t1 = time.time()
total = t1-t0
print(total)

始终尝试在多个范围内测量 empirical complexity 代码。

你的代码很慢,因为你找到集合差异的方式,而且你总是在集合和列表之间来回转换。您应该始终使用一套,并使用

对其进行更新
    sete.difference_update(range(p*p,n,p*2))

要查找最小元素,只需调用集合上的 min(sete) 即可,无需列表转换。

由于对 min 元素的低效搜索,最终代码的整体复杂度将接近 n^1.5,这不算太亮,但也不算太糟糕。特别是,它在 ideone.com 上用不到 4.9 秒完成,找到 2000000 以下素数的总和,400000 以下的素数总和为 0.5 秒(首先对仅使用赔率进行了额外优化)。