https://projecteuler.net/problem=35
Project Euler上的所有问题都应该由程序在1分钟内解决。但是,我的解决方案的运行时间大约为3分钟。我在网上看到的其他解决方案在概念上与我的相似,但运行时间指数更快。任何人都可以帮助我提高代码效率/运行更快吗?
谢谢!
#genPrimes takes an argument n and returns a list of all prime numbers less than n
def genPrimes(n):
primeList = [2]
number = 3
while(number < n):
isPrime = True
for element in primeList:
if element > number**0.5:
break
if number%element == 0 and element <= number**0.5:
isPrime = False
break
if isPrime == True:
primeList.append(number)
number += 2
return primeList
#isCircular takes a number as input and returns True if all rotations of that number are prime
def isCircular(prime):
original = prime
isCircular = True
prime = int(str(prime)[-1] + str(prime)[:len(str(prime)) - 1])
while(prime != original):
if prime not in primeList:
isCircular = False
break
prime = int(str(prime)[-1] + str(prime)[:len(str(prime)) - 1])
return isCircular
primeList = genPrimes(1000000)
circCount = 0
for prime in primeList:
if isCircular(prime):
circCount += 1
print circCount
答案 0 :(得分:0)
对代码进行两次修改会产生一个非常快速的解决方案(在我的机器上大约2秒):
生成素数是网络上许多解决方案的常见问题。我使用this article中的rwh_primes1
替换了你的
def genPrimes(n):
sieve = [True] * (n/2)
for i in xrange(3,int(n**0.5)+1,2):
if sieve[i/2]:
sieve[i*i/2::i] = [False] * ((n-i*i-1)/(2*i)+1)
return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]
它快了约65倍(0.04秒)。
然而,我建议的最重要的一步是过滤生成的素数列表。由于整数的每个循环移位版本必须是素数,因此圆形素数不得包含某些数字。例如,素数23
可以很容易地被发现为无效候选者,因为它包含2
,当这是最后一位数时,它表示两个可分性。因此,您可以通过以下简单方法删除所有这些不良候选人:
def filterPrimes(primeList):
for i in primeList[3:]:
if '0' in str(i) or '2' in str(i) or '4' in str(i) \
or '5' in str(i) or '6' in str(i) or '8' in str(i):
primeList.remove(i)
return primeList
请注意,循环从第四个素数开始,以避免删除数字2
或5
。
过滤步骤占用了大部分计算时间(约1.9秒),但是将循环质数候选者的数量从78498急剧减少到1113(减少了98.5%)!
最后一步,每个剩余候选人的流通,可以按照你的建议完成。如果您愿意,可以按如下方式简化代码:
circCount = sum(map(isCircular, primeList))
由于候选集减少,此步骤仅在0.03秒内完成。