Python素数代码运行缓慢

时间:2011-03-06 01:42:29

标签: python algorithm data-structures primes

我正在尝试解决此处提到的问题:https://www.spoj.pl/problems/PRIME1/

我也在下面给出描述。

  

彼得想为他的密码系统生成一些素数。帮助他!你的任务是生成两个给定数字之间的所有素数!

     

输入

     

输入以单行中的测试用例的数量t开始(t <= 10)。在下一个t行的每一行中,有两个数字m和n(1 <= m <= n <= 1000000000,n-m <= 100000)由空格分隔。

     

输出

     

对于每个测试用例,打印所有素数p,使得m <= p <= n,每行一个数,由空行分隔的测试用例。

我的代码如下。我在想列表上的删除方法很慢。

import sys
import math

num = int(sys.stdin.readline());
indices = []
maxrange = 2
while(num > 0):
    a,b = sys.stdin.readline().split(" ");
    a = int(a)
    b = int(b)
    if(a < 2):
        a = 2
    indices.append((a,b))
    if(b > maxrange):
        maxrange= b          
    num = num - 1

val = int(math.sqrt(maxrange)+1)
val2 = int(math.sqrt(val)+1)
checks = range(2,val2)

for i in range(2,val2):
    for j in checks:
        if(i!= j and j%i == 0):
            checks.remove(j)

primes = range(2,val)
for i in checks:
    for j in primes:
        if(i != j and j%i == 0):
            primes.remove(j)

primes2 = range(2,maxrange)
for i in primes:
    for j in primes2:
        if(j != i and j%i == 0):
            primes2.remove(j)

for (a,b) in indices:
    for p in primes2:
        if(a<= p and b >= p):
            print p
        if(p > b):
            break
    print

我认为删除python列表非常慢。我的代码是正确的但我超时限制。有人可以帮我改进这段代码。

4 个答案:

答案 0 :(得分:3)

素性测试功能表现最佳。 Miller-Rabin wikipedia page

上有伪代码

答案 1 :(得分:2)

为什么不用一些标记值替换它,而不是删除不是素数的元素,可能是-1None?然后在打印时,只需打印非标记的值。

使用长度为(n-m)的列表,然后数字i的索引为x[m+i]

答案 2 :(得分:1)

remove()在宏观方案中并不慢,只是代码称之为很多。

正如dappawit建议的那样,不是修改列表,而是更改列表中的值,以便您知道它不是一个有效的数字。

我也看到当你生成素数集时,你使用range(2,maxrange)这是可以的,但如果下界远大于2则效率不高。你将浪费计算时间来生成素数甚至与问题空间无关。如果不出意外,请跟踪minrange和maxrange。

原始代码的一个错误是您使用range(2,maxrange)。这意味着maxrange不在所考虑的数字列表中。尝试使用3 5作为a和b的输入来查看错误。

range(2,maxrange+1)解决了这个问题。

代码中的另一个错误是您修改了原始序列:

来自Python docs - for-statement

  

修改循环中迭代的序列是不安全的(这只能发生在可变序列类型中,例如列表)。如果您需要修改正在迭代的列表(例如,复制所选项目),则必须迭代副本。切片表示法使这特别方便:

我的python技能很简陋,但这似乎有效:

旧:

primes2 = range(2,maxrange)
for i in primes:
     for j in primes2:
         if(j != i and j%i == 0):
             primes2.remove(j)

for (a,b) in indices:
    for p in primes2:
        if(a<= p and b >= p):

新:

primes2 = array.array('L', range(minrange,maxrange+1))
for i in primes:
    for j in primes2:
        if(j != i and j%i == 0):
            primes2[j-minrange] = 0

for (a,b) in indices:
    for p in primes2:
        if (p != 0):
            if(a<= p and b >= p):

您还可以跳过生成素数集并直接测试数字,如果您必须生成素数的数字集不重叠(没有工作重复),这将起作用。 enter link description here

答案 3 :(得分:1)

这是Python中小奇数整数Miller–Rabin primality test的确定性变体:

from math import log

def isprime(n):
    assert 1 < n < 4759123141 and n % 2 != 0, n

    # (n-1) == 2**s * d
    s = 0
    d = n-1
    while d & 1 == 0:
        s += 1
        d >>= 1
    assert d % 2 != 0 and (n-1) == d*2**s

    for a in [2, 7, 61]:
        if not 2 <= a <= min(n-1, int(2*log(n)**2)):
            break
        if (pow(a, d, n) != 1 and
            all(pow(a, d*2**r, n) != (n-1) for r in xrange(s))):
            return False
    return True

代码意图是可执行的伪代码。