Python 2正整数列表查找素数

时间:2013-10-12 21:35:37

标签: python algorithm primes

给出2个正整数列表,找出从每个列表中选择一个数字的方式,使其总和为素数。

我的代码太慢因为我有list1和list 2,每个包含50000个数字。所以任何方式使它更快,所以它在几分钟而不是几天解决它? :)

    # 2 is the only even prime number
    if n == 2: return True

    # all other even numbers are not primes
    if not n & 1: return False

    # range starts with 3 and only needs to go 
    # up the squareroot of n for all odd numbers
    for x in range(3, int(n**0.5)+1, 2):
        if n % x == 0: return False

    return True



for i2 in l2:
    for i1 in l1:
        if isprime(i1 + i2):
            n = n + 1 # increasing number of ways
            s = "{0:02d}: {1:d}".format(n, i1 + i2)
            print(s) # printing out

3 个答案:

答案 0 :(得分:2)

草图:

  1. 按照@ Steve的建议,先找出所有素数< = max(l1) + max(l2)。我们将该列表primes称为。注意:primes并不需要成为一个列表;你可以改为generate primes up the max一次。

  2. 交换列表(如有必要),以便l2是最长的列表。然后将其转换为集合:l2 = set(l2)

  3. 排序l1l1.sort())。

  4. 然后:

    for p in primes:
        for i in l1:
            diff = p - i
            if diff < 0:
                # assuming there are no negative numbers in l2;
                # since l1 is sorted, all diffs at and beyond this
                # point will be negative
                break
            if diff in l2:
               # print whatever you like
               # at this point, p is a prime, and is the
               # sum of diff (from l2) and i (from l1)
    

    唉,如果l2是,例如:

    l2 = [2, 3, 100000000000000000000000000000000000000000000000000]
    

    这是不切实际的。它依赖于此,在您的示例中,max(max(l1), max(l2))是&#34;相当小&#34;。

    充实

    哼!您在评论中说,列表中的数字长达5位数。所以他们不到10万。你在开始时说过,这个列表每个都有50,000个元素。因此,它们各自包含大约100,000的所有可能整数的一半,并且您将拥有非常大量的素数作为素数。如果你想进行微观优化,这一切都很重要; - )

    无论如何,由于最大可能总和小于200,000,任何筛选方式都足够快 - 它将是运行时的一个微不足道的部分。这是代码的其余部分:

    def primesum(xs, ys):
        if len(xs) > len(ys):
            xs, ys = ys, xs
        # Now xs is the shorter list.
        xs = sorted(xs)  # don't mutate the input list
        sum_limit = xs[-1] + max(ys)  # largest possible sum
        ys = set(ys)     # make lookups fast
        count = 0
        for p in gen_primes_through(sum_limit):
            for x in xs:
                diff = p - x
                if diff < 0:
                    # Since xs is sorted, all diffs at and
                    # beyond this point are negative too.
                    # Since ys contains no negative integers,
                    # no point continuing with this p.
                    break
                if diff in ys:
                    #print("%s + %s = prime %s" % (x, diff, p))
                    count += 1
        return count
    

    我不会提供我的gen_primes_through(),因为它无关紧要。从其他答案中选择一个,或自己编写。

    这是提供测试用例的便捷方式:

    from random import sample
    xs = sample(range(100000), 50000)
    ys = sample(range(100000), 50000)
    print(primesum(xs, ys))
    

    注意:我使用的是Python 3.如果您使用的是Python 2,请使用xrange()代替range()

    在两次跑步中,每次跑步大约需要3.5分钟。这就是你在开始时要求的(&#34;分钟而不是几天和#34;)。 Python 2可能会更快。返回的计数是:

    219,334,097
    

    219,457,533
    

    可能的总金额当然是50000 ** 2 == 2,500,000,000。

    关于时间安排

    所有此处讨论的方法,包括您原来的方法,花费时间与两个列表的产品成比例&#39;长度。所有的摆弄都是为了减少常数因素。这是对原作的巨大改进:

    def primesum2(xs, ys):
        sum_limit = max(xs) + max(ys)  # largest possible sum
        count = 0
        primes = set(gen_primes_through(sum_limit))
        for i in xs:
            for j in ys:
                if i+j in primes:
                    # print("%s + %s = prime %s" % (i, j, i+j))
                    count += 1
        return count
    

    也许你会更好地理解这一点。为什么这是一个巨大的进步?因为它用快速的设置查找替换了昂贵的isprime(n)函数。它仍然需要与len(xs) * len(ys)成比例的时间,但是比例常数和#34;通过以非常便宜的操作替换非常昂贵的内循环操作来削减。

    事实上,primesum2()在很多情况下也比primesum()快。使你的具体案例更快primesum()的原因是,只有大约18,000个素数小于200,000。因此,遍历素数(如primesum()所做的那样)比使用50,000个元素的列表迭代要快得多。

    A&#34;快速&#34;这个问题的通用函数需要根据输入选择不同的方法。

答案 1 :(得分:1)

您应该使用Sieve of Eratosthenes来计算素数。

您还计算每种可能的总和组合的素数。相反,请考虑使用列表中的总和来查找可以达到的最大值。生成所有素数的列表,直到该最大值。

当您将这些数字相加时,您可以看到该数字是否出现在您的素数列表中。

答案 2 :(得分:1)

我会在每个范围内找到最高的数字。素数范围是最高数字的总和。

以下是筛选素数的代码:

def eras(n):
    last = n + 1
    sieve = [0, 0] + list(range(2, last))
    sqn = int(round(n ** 0.5))
    it = (i for i in xrange(2, sqn + 1) if sieve[i])
    for i in it:
        sieve[i * i:last:i] = [0] * (n // i - i + 1)
    return filter(None, sieve)

大约需要3秒才能找到高达10 000 000的素数。然后我将使用您用于生成总和的n ^ 2算法。我认为有n logn算法,但我无法想出来。

它看起来像这样:

from collections import defaultdict
possible = defaultdict(int)
for x in range1:
    for y in range2:
        possible[x + y] += 1

def eras(n):
    last = n + 1
    sieve = [0, 0] + list(range(2, last))
    sqn = int(round(n ** 0.5))
    it = (i for i in xrange(2, sqn + 1) if sieve[i])
    for i in it:
        sieve[i * i:last:i] = [0] * (n // i - i + 1)
    return filter(None, sieve)

n = max(possible.keys())
primes = eras(n)
possible_primes = set(possible.keys()).intersection(set(primes))

for p in possible_primes:
    print "{0}: {1} possible ways".format(p, possible[p])