任务取自www.codewars.com
素数的间隔不是规则的。例如从2到3步骤是1。从3到5,步长为2。从7点到11点是4点。在2和50之间,我们有以下两对2步素数:
3,5-5,7,-11,13,-17,19,-29,31,-41,43
我们将编写一个带有参数的函数步骤:
g(整数>=2(,表示我们正在寻找的步骤,
m(整数>=2(,其给出搜索的开始(包括m(,
n(整数>=m(,其给出搜索的结束(包括n(
在上面的例子中,步骤(2,2,50(将返回[3,5],它是第一对介于2和50之间,具有2步。
所以这个函数应该返回两个素数的第一对在极限m,n之间间隔一个g阶,如果这些g阶素数数字以其他方式存在nil或null或None或Nothing或[]或";0;或{0、0}或0 0(取决于语言(。
示例:步骤(2,5,7(->[5,7]或(5,7(或{5,7}或";57〃;
步骤(2,5,5(->零或。。。或Ocaml中的[]或C++中的{0,0}
步骤(4130200(->[163167]或(163167(或{163167}
请参阅";测试";
备注:([193197]也是这样一个介于130和200之间的4阶素数但这不是第一对(。
步骤(6100110(->[101107]尽管在101之间有素数以及107,其为103;对101-103是2步。
这是我的解决方案,它工作得很好,需要比测试更多的时间,但是,我正在尝试优化此代码,以使其更节省时间
def step(g,m,n):
count = 0
list= []
list2 = []
for num in range(m,n+1):
if all(num%i!=0 for i in range(2,num)):
count += 1
list.append(num)
for k in list:
for q in list:
if (q-k) > 0:
if (q-k) == g:
list2.append(k)
list2.append(q)
if not list2:
return
else:
return [list2[0],list2[1]]
如果您有任何建议,甚至是示例代码,我将不胜感激
首先,从不使用关键字作为变量。
为了找到更好的方法,你需要考虑你方法中的缺陷。
- 您正在迭代所有的数字来确定素数
- 您正在遍历O(n**2(中的列表,以确定是否存在具有所需差异的对
- 你的素数计算算法不是最优的
对于第一点,甚至不需要找到给定范围内的所有素数,因为您的任务是找到具有所需差异的第一对。所以,如果你找到数字a
是素数,a + g
也是素数,那么你已经找到了解。
对于第二点,您可以简单地遍历列表,并检查if (k + g) in list
以确定是否找到了对。
对于第三点,您可以在维基百科页面本身上找到一个最佳实现。如果您能够理解逻辑,那么您可以非常容易地自己编写实现。
因此,将最佳素数检查实现与单循环迭代相结合,可以很容易地编写解决方案,如下所示。
from functools import lru_cache
@lru_cache(None)
def is_prime(n):
if n <= 3:
return n > 1
if n % 2 == 0 or n % 3 == 0:
return False
i = 5
while i ** i <= n:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True
def step(g, m, n):
for i in range(m, n + 1 - g):
if is_prime(i) and is_prime(i + g):
return [i, i + g]
return
对于step(4, 130, 200)
的1000000次迭代,此实现仅用了1.32秒。正如您所看到的,一旦实现了is_prime
函数,逻辑就非常简单。