生成列表a(n)的形式不是素数+ a(k),k <n

时间:2018-09-03 09:58:30

标签: python algorithm math sequence

如何在Python中生成此列表?     a(n)的形式不是素数+ a(k),k

以下是oeis http://oeis.org/A025043

上的列表

分别为0、1、9、10、25、34、35、49、55、85、91、100、115、121。

我尝试了大胆的方式,但效果不佳。现在,我正在寻找一种复杂的解决方案,例如Eratosthenes的Sieve作为素料。 大胆的方法要求迭代每个素数,并且对于素数的每次迭代,都迭代序列中已经存在的每个数字,这需要很长时间。

该表由聪明的人生成:http://oeis.org/A025043/b025043.txt 他们要么使用大量计算能力,要么使用我正在寻找的复杂算法。

  

为解释此序列是什么,可以将序列中不存在的每个数字表示为该序列中质数和数字的总和。例如8 = 7(素数)+ 1(顺序),54 = 53(素数)+1(顺序),等等。

2 个答案:

答案 0 :(得分:7)

生成此序列的明显方法是生成所有素数,然后使用筛子。对于找到的序列中的每个新元素x,在所需范围内删除所有素数x+p的{​​{1}}。

mathoverflow注释猜测该序列的密度趋于N / sqrt(ln N)。如果正确,那么此代码将在时间O(N ^ 2 /(ln N)^ 3/2)中运行。 (使用小于N的素数数约为N / ln N)。

一旦N达到10 ^ 6,这将非常慢,但是在我的桌面上运行代码表明即使N = 10 ^ 7,您也将在几小时内获得完整列表。请注意,该算法变得越来越快,因此不要因初始缓慢而过分推迟。

Python 3代码:

p

用C重新编写它,并使用import array N = 10000 def gen_primes(N): a = array.array('b', [0] * (N+1)) for i in range(2, N+1): if a[i]: continue yield i for j in range(i, N+1, i): a[j] = 1 def seq(N): primes = list(gen_primes(N)) a = array.array('b', [0] * (N+1)) for i in range(N+1): if a[i]: continue yield i for p in primes: if i + p > N: break a[i+p] = 1 for i in seq(N): print(i, end=' ', flush=True) print() 进行编译可以提供更快的解决方案。这段代码会在我的计算机上的7分30秒内生成最多10 ^ 7的列表:

gcc -O2

答案 1 :(得分:3)

Eratosthenes的筛子看起来与素数筛子非常相似。但是您需要从素数列表开始。

使用质数时,您有一堆i * prime(k)项,其中prime是我们的序列,i是序列中每个元素的增加量。

这里有一堆prime(i) + a(k)项,其中a是我们的序列,i是我们为序列中每个元素增加的量。

当然,+而不是*在整体效率上有很大的不同。

下面的代码在几秒钟内达到100k,因此如果要生成特别大的数字,它将变得很慢。

您可以等待,看看是否有人想出一种更快的方法。

# taken from https://stackoverflow.com/questions/3939660
def primes_sieve(limit):
    a = [True] * limit
    a[0] = a[1] = False

    for (i, isprime) in enumerate(a):
        if isprime:
            yield i
            for n in range(i*i, limit, i):
                a[n] = False

def a_sieve(limit, primes):
    a = [True] * limit
    for (i, in_seq) in enumerate(a):
        if in_seq:
            yield i
            for n in primes:
                if i+n >= limit:
                    break
                a[i+n] = False

primes = list(primes_sieve(100000))
a = list(a_sieve(100000, primes))
# a = [0, 1, 9, 10, 25, 34, 35, 49, 55, 85, 91, 100, 115, 121, 125, 133, 145, ...]

为了进行比较,我编写了下面的蛮力方法,一种方法迭代素数并检查是否减法给出了序列中的元素,另一种方法迭代了素数并检查我们是否得到素数,这两种方法都需要大约是100k的两倍。

它看起来确实与Sieve相似,但是它向后看而不是向前设置值。

def a_brute(limit, primes):
    a = [True] * limit
    for i in range(limit):
        for p in primes:
            if i-p < 0:
                yield i
                break
            if a[i-p]:
                a[i] = False
                break
        else:
            yield i

def a_brute2(limit, primes_sieve):
    a = [True] * limit
    l = []
    for i in range(limit):
        for j in l:
            if i-j < 0:
                l.append(i)
                break
            if primes_sieve[i-j]:
                a[i] = False
                break
        else:
            l.append(i)
    return l

结果:

Primes sieve: 0.02 seconds
Sieve: 6.26 seconds
Brute force 1: 14.14 seconds
Brute force 2: 12.34 seconds