当前位置: 首页 > 知识库问答 >
问题:

试图解决Project Euler#10,但是代码需要*很多*时间来显示输出

连昊天
2023-03-14

欧拉计划问题10:

低于10的素数之和为2 3 5 7=17。

求200万以下所有素数之和。

我认为我的代码中没有任何错误。但给出答案确实需要很多时间。我尝试过使用PyPy,因为我听说它比CPython解释器快,但仍然不行。

代码如下:

#Implementation of Sieve of Eratosthenes
def prime_sieve(limit):
    primes = range(2, limit)
    for i in primes:
        for j in range(2, primes[-1]):
            try:
                primes.remove(i*j)
            except ValueError:
                pass

    return primes;


answer = 0

for x in prime_sieve(2000000):
    answer += x

print "Answer: %d." % answer
raw_input()

共有3个答案

景帅
2023-03-14

一个更有效的想法是这样的:

你从列表开始:

[0,1,2,3,4,5,6,7,8,9,10]

您希望将每个非素数元素都设置为0,并保留素数。

将0和1设置为零,因为它们不是素数。从现在起,您需要执行以下两个步骤:

1) 找到你还没有考虑过的最小素数,我们称之为n

2)设置每个第n个元素为0(但不是n),因为它们是n的倍数

例如:将0和1设置为0s后:

[0,0,2,3,4,5,6,7,8,9,10]

您没有考虑的最小素数是2,因此您将每秒钟的元素设置为零(但不是2):

[0,0,2,3,0,5,0,7,0,9,0]

您没有考虑的最小素数是3,所以您将每三个元素设置为零(但不是3),以此类推...:

[0,0,2,3,0,5,0,7,0,0,0]

另外请注意,您不必对每个素数都这样做,一旦素数达到sqrt(限制),您就可以停止,因为您知道所有非素数都已设置为零。

例如,10的平方根(本例中的限制)是3.162,这意味着当我们达到5时,我们不需要做任何事情,我们在这一点上完成了。但为什么呢?我们使用每个素数将其倍数设置为零,因为这些倍数不是素数;但是,由于5大于10的平方根,因此5的任何倍数都必须是小于5的数字的倍数,因此已经设置为0。

假设我们最初的范围是从20。20的平方根小于5,所以我们不需要检查5,因为5: 5 * 2 = 10, 5 * 3 = 15, 5 * 2 * 2 = 20的所有倍数都是较小素数的倍数,我们已经将它们设置为0。

邹书
2023-03-14

质点筛的正确数据结构是一个位集,由整数值索引。Python没有一个内置的,但是因为你的限制很小(只有200万),一个常规的整数列表应该适合内存,即使它浪费了30倍或更多(它将需要大约9 MB的等效位集C需要250 KB)。

要提高速度,最重要的一点是除非通过直接索引(因此没有删除/删除),否则永远不要访问数组。此外,将筛的外循环限制为sqrt(限制),并将循环前进到下一个素数,而不是下一个值。

因此,类似这样的操作应该非常快(在我的旧机器上,使用香草Python 2.7大约需要2秒钟)。

import math, sys

def prime_sieve(limit):
    # Mark everything prime to start
    primes = [1 for x in xrange(limit)]
    primes[0] = 0
    primes[1] = 0

    # Only need to sieve up to sqrt(limit)
    imax = int(math.sqrt(limit) + 1)

    i = 2
    while (i < imax):
        j = i + i
        while j < limit:
            primes[j] = 0
            j += i

        # Move i to next prime
        while True:
           i += 1
           if primes[i] == 1:
               break

    return primes

s = prime_sieve(2000000)
print(sum(i for i in xrange(len(s)) if s[i] == 1))
秦胡媚
2023-03-14

问题是:

primes.remove(i*j)

。remove()在大型列表上调用时效率非常低,因为它首先必须遍历整个列表以确定值的存在位置(如果有),然后必须再次遍历列表的一部分,以将移除元素后的所有元素向下移动一个位置。

这里还有其他使用数据结构的方法(包括使用列表的其他方法和完全使用其他数据结构的方法)会更有效。

最后:您的代码在迭代的同时修改primes(primes中的i就是这样做的)。这通常被认为是一件坏事,因为在迭代时修改某些内容可能是未定义的行为。

 类似资料:
  • 升级到macOS Sierra后,“sbt测试”(包括查找本地主机名/IP地址)的性能似乎有问题。在以前版本的OSX上,完成该操作大约需要40-50秒。macOS Sierra时间远高于此。我最后一次跑步大约15分钟。编译时间与“El Capitan”上的编译时间大致相同。 我是我团队中唯一一个尝试这款新苹果电脑的人,所以我不知道它是只发生在我的苹果电脑上,还是一个普遍的问题。 我的同事在Ubun

  • 我有一个Android应用程序。在启动屏幕的方法中,我添加了 因此,我希望在onCreate退出后100ms后执行该代码。 但我可以看到,我的应用程序在onCreate()之后花了3秒时间来执行延迟后的代码(在3秒之后还会出现UI): 有人能告诉我为什么一个应用程序可以在onCreate()之后花3秒来执行延迟后的代码和UI开始出现? 请建议我如何优化这一次的技巧? 还有一个问题,Handler.

  • 我启动了一个项目,现在项目中有大约7个测试,使用执行整个测试套件已经花费了一分钟多的时间。 从附加输出(标志)中,我可以看到,对于每个测试类和方法,整个quarkus应用程序以及mongodb实例等依赖项都会重新启动。 这与quarkus文档在测试指南页面上的内容完全相反: 到目前为止,在我们的所有示例中,我们只为所有测试启动Quarkus一次。在运行第一个测试之前,Quarkus将启动,然后所有

  • 我使用javamail通过IMAP协议从exchage帐户读取邮件。这些邮件是纯格式的,内容是XML。 几乎所有这些邮件的大小都很短(通常小于100Kb)。然而,有时我不得不处理大型邮件(大约10Mb-15Mb)。例如,昨天我收到一封13Mb大小的电子邮件。仅仅读它就花了50多分钟。这正常吗?有没有办法提高它的性能?代码是: 花费如此长时间的方法是。我做错了什么?有什么提示吗? 非常感谢,我的英语

  • 问题内容: 我在从2.2-4.1.2测试的所有Android版本中都遇到了这种情况。 这些流的比特率适合移动和3G连接。同一流只需不到一秒钟的时间即可开始在等效的iOS应用中进行缓冲。 有没有一种方法可以指定应该缓冲的时间?我知道Tune In广播应用程序提供此功能(https://play.google.com/store/apps/details?id=tunein.player)。 谢谢。

  • 我使用的是intellij和junit-jupiter-api-5.7.2和mockito-core-3.9.0。我使用了正确的RunWith注释,所有的公共测试都有@test。在SomeBusinessImpl中,方法都是公共的。我不明白为什么会发生org.mockito.exceptions.base.MockitoException错误。 下面是我要测试的类 如果有人能帮助我,真的很感激,谢