python - Python:减少运行时间?
问题描述
我最近开始学习 python,并且正在使用 CodeWars 进行训练。任务是返回一个列表[p, p + 4, p + 6, p + 10, p + 12, p + 16]
,其中所有这些都是素数。它们的总和应该高于 sum_limit。对于低值,它正在工作,但在高值(约 200 万)时,运行时间很高。如何减少运行时间?
from math import sqrt; from itertools import count, islice
def find_primes_sextuplet(sum_limit):
for x in range(sum_limit):
if isPrime(x) and isPrime(x+4) and isPrime(x+6) and isPrime(x+10) and isPrime(x+12) and isPrime(x+16):
possible = [x, x+4, x+6, x+10, x+12, x+16]
if sum(possible) > sum_limit:
return possible
def isPrime(n):
return n > 1 and all(n%i for i in islice(count(2), int(sqrt(n)-1)))
print(find_primes_sextuplet(2000000))
解决方案
这是我关于降低复杂性和运行时间的想法。
你可以写一个筛子O(n log log n)
。这是一个合理的实现:
def sieve(n):
grid = [None for _ in range(n+1)]
i = 2
while i < n+1:
if grid[i] is None:
grid[i] = True
for p in range(2*i, n+1, i):
grid[p] = False
else:
i += 1
return (index for index, b in enumerate(grid) if b)
有 6 个数字,加到第一个数字的总数是 48。所以第一个数字的最小可能值为(n - 48) / 6
。在我的筛子中,我们可以迭代生成器,直到 number 大于该值。
def get_remaining_sieve(n):
g = sieve(n)
current = next(g)
min_value = (n - 48) / 6
while current < min_value:
current = next(g)
return [current] + list(g)
现在只需遍历长度为 6 的每个切片,并检查分隔是否与所需的分隔匹配(4、2、4、2、4)。
remaining = get_remaining_sieve(n)
for start in range(len(remaining) - 5):
slice = remaining[start:start+6]
differences = [slice[j] - slice[j-1] for j in range(1, 6)]
if differences == [4, 2, 4, 2, 4]:
print(slice)
概括
基于这些原则,我想出了这个解决方案:
from itertools import dropwhile, islice
def get_solutions(n):
grid = [None for _ in range(n+1)]
i = 2
while i < n+1:
if grid[i] is None:
grid[i] = True
for p in range(2*i, n+1, i):
grid[p] = False
else:
i += 1
sieve = (index for index, b in enumerate(grid) if b)
min_value = (n - 48) / 6
reduced_sieve = dropwhile(lambda v: v < min_value, sieve)
reference_slice = list(islice(reduced_sieve, 6))
while True:
try:
ref = reference_slice[0]
differences = [v - ref for v in reference_slice[1:]]
if differences == [4, 6, 10, 12, 16]:
yield reference_slice
reference_slice = reference_slice[1:] + [next(reduced_sieve)]
except StopIteration:
break
n = 2000000
print(next(get_solutions(n))) # 695ms
# or for all solutions
for solution in get_solutions(n): # 755ms
print(solution)
这在我的计算机上运行不到一秒钟。
推荐阅读
- python - 如何在不修改代码的情况下禁用在 pytest 中跳过测试?
- sql - Illuminate\Database\QueryException (HY093) SQLSTATE[HY093]: 参数号无效
- python - 如何修复连接到“wrds”数据库的错误?
- java - 执行 AsyncTask 时无法解析符号“执行”
- jenkins-pipeline - 共享库“vars”文件夹结构 - 我可以添加子文件夹吗?
- angular - Angular - 自定义 ngx-bootstrap Typeahead 以根据逗号分隔的多个值自动完成
- java - 视图关闭时如何杀死从 JavaFX 控制器产生的线程
- r - R中的Levene事后测试
- spring - 没有@Qualifier 的@AutoWired
- php - 密码重置在验证时不返回错误消息