我有一个任务,我需要在Python中找到包含65个以上质数的最低Collatz序列。在
例如,19的Collatz序列是:
19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1
7素数序列包含这个。在
我还需要使用回忆录,这样它就不必运行一年来找到它。我找到了Collatz序列记忆的代码,但我不知道当我只需要素数时,如何让它工作。在
这是我找到的Collatz记忆代码:
lookup = {}
def countTerms(n):
if n not in lookup:
if n == 1:
lookup[n] = 1
elif not n % 2:
lookup[n] = countTerms(n / 2)[0] + 1
else:
lookup[n] = countTerms(n*3 + 1)[0] + 1
return lookup[n], n
这是我的prime测试仪:
^{pr2}$
让我们从一个确定一个数是否为素数的函数开始;我们将使用Miller-Rabin算法,它比我们要处理的数字大小的试除法快:
由于我们想找到满足条件的第一个数,我们的策略是从2开始,逐步向上,并在进行时存储结果。我们用Collatz序列中从0到2的素数来初始化缓存(这是一个糟糕的双关语,抱歉):
^{pr2}$函数
pCount(n)
计算Collatz序列中的素数。一旦序列的当前值k下降到n以下,我们就在缓存中查找结果。在此之前,我们测试Collatz序列中的每个奇数是否素数,并在适当的情况下增加素数p。当我们有了n的素数时,我们将其添加到缓存并返回它。在现在只需计算每个n的素数,从3开始,当素数超过65时停止:
用不了多久,在我的电脑上不到一分钟。结果如下:
结果中有67个素数。如果您想看到它们,这里有一个简单的函数,它打印给定n的Collatz序列:
下面是素数的列表:
多么有趣的休闲数学问题!在
编辑:既然有人问过Miller-Rabin素性测试仪,让我展示一下这个基于2,3,5轮的简单素性测试仪;它用2,3,5和不是2,3,5的倍数的数字进行试除法,这包括一些复合物,所以用素数进行试除法效率有点低,但是不需要预先计算和存储素数,所以使用起来更容易。在
说
filter(isPrime,range(1000000))
可以在几秒钟内识别出小于100万的78498个素数。您可能需要将这个素性测试仪的计时与Miller-Rabin测试仪进行比较,并根据运行时效率确定交叉点的位置;我没有做任何正式的计时,但它似乎在与Miller-Rabin-tester差不多的时间内解决了65 collatz prime问题。或者你可能想把试飞师和2,3,5轮组合在一起,达到一定的限制,比如1000,10000或25000,然后对幸存者进行米勒拉宾测试;这很快消除了大多数合成物,所以它可以很快运行。在现有代码缩进错误。我假设这个任务是一个家庭作业任务,所以我不会发布一个完整的解决方案,但我会给你一些有用的片段。在
首先,这里有一个稍微更有效的素性测试程序。它不是测试所有小于
a
的数字是否都是a
的因子,而是测试a
的平方根。在请注意,此函数为
^{pr2}$a = 1
返回True
。没关系,因为您不需要测试1:您可以将它预加载到lookup
dict中:您的
countTerms
函数需要稍作修改,以便在当前n
为素数时,它只在lookup
计数中添加一个。在Python中,False
的数值为0,True
的数值为1。这里很方便:我已经把函数名改成了Pythonic。在
FWIW,第一个包含65个或更多素数的Collatz序列实际上包含67个素数。它的种子数超过180万个,当检查到该种子的所有序列时,需要进行素性测试的最高数目是151629574372。完成时,
lookup
dict包含3920492个条目。在为了回应jamesmills关于递归的评论,我写了一个非递归的版本,为了容易地看到迭代版本和递归版本都产生相同的结果,我发布了一个完整的工作程序。我在上面说过我不打算这么做,但我认为现在这样做应该是可以的,因为spørreren已经使用我在原始答案中提供的信息编写了他们的程序。在
我完全同意避免递归是好的,除非它适合于问题域(例如,树遍历)。Python不鼓励递归-它不能优化尾部调用递归,它施加了递归深度限制(尽管如果需要,可以修改该限制)。在
这个Collatz序列素数计算算法自然地递归地表示,但是迭代地做并不难——我们只需要一个列表,在确定序列所有成员的素数时暂时保存序列。这个版本可能需要更多的内存空间。在
当在操作中解决问题时,递归版本达到了343的递归深度。这在默认限制范围内,但仍然不好,如果你想搜索包含更多素数的序列,你会达到这个极限。在
迭代和递归版本的运行速度大致相同(至少在我的机器上是这样)。要解决OP中提到的问题,他们都需要不到2分钟的时间。这比我原来的解决方案快得多,主要是由于素性测试中的优化。在
基本的Collatz序列生成步骤已经需要确定一个数是奇数还是偶数。显然,如果我们已经知道一个数是偶数,那么就没有必要测试它是否是质数。:)我们还可以消除
is_prime
函数中的偶数因子测试。我们只需将2的结果加载到lookup
缓存中,就可以处理2是素数这一事实。在另一方面,当搜索包含给定数量素数的第一个序列时,我们不需要测试任何从偶数开始的序列。偶数(除了2)不会增加序列的素数,而且由于这样一个序列中的第一个奇数将比我们当前的数字低,所以假设我们从3开始搜索,它的结果将已经在
lookup
缓存中。如果我们不从3开始搜索,我们只需要确保我们的起始种子足够低,这样我们就不会意外地错过包含所需数量素数的第一个序列。采用这种策略不仅减少了所需的时间,还减少了项目的数量在查找缓存中。在当与
$ ./CollatzPrimes.py 65
输出是
相关问题 更多 >
编程相关推荐