我想找到Spoiler alert Euler #41 problem
的解决方案。我问过的问题是它的子问题。我有问题的解决方案,但问题在于解决方案。这是我要检查的实际内容: -
large = 0
x = ''
for i in range(1,10):
x += '%d' %i
for perm in permutations(x):
if(isPrime(int(perm))):
large = perm
print large
这里是排列函数: -
def permutations(val):
res = []
if len(val) == 1:
res = [val]
else:
for i, c in enumerate(val):
for perm in permutations(val[:i]+val[i+1:]):
res += [c+perm]
return res
上述程序从1到987654321找到排列中所有素数的排列。
但问题是在大= 7652413之后,没有进一步的增长。程序在大约3秒内达到此值,但程序在大约4分钟内完成。所以我想知道是否有任何方法可以减少时间。
这个问题也可以概括为一种方法,可以找出一个函数,它告诉你函数是否花费太长时间来获得所需的结果。
答案 0 :(得分:2)
只回答手头的直接问题,您可以使用itertools.permutations
显着加快代码速度。
但是,从数学上讲,你可以通过意识到你想要的素数最多可以有7位来减少你的问题。如果它有8,那么1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 = 36
,它可以被3整除,所以不能是素数。添加9得到45,也可以被3整除。
答案 1 :(得分:1)
听起来你正在寻找一种方法来应用超时作为启发式来告诉你“你可能已经完成”,然后停止工作。
这样做的简单方法是在开始时或每次增加large
时获取当前时间(取决于您认为相关的那个),然后经常检查时间并取消如果你经过它。
如果在你的代码中手动“经常检查”是不合理的,你可以使用后台线程来做,但让我们保持简单,因为这里似乎没有必要。
所以:
class Timeout(object):
def __init__(self, timeout_seconds):
self.timeout = datetime.timedelta(0, timeout_seconds)
self.reset()
def reset(self):
self.start = datetime.datetime.now()
self.stop = self.start + self.timeout
def check(self):
if datetime.datetime.now() > self.stop:
raise Exception('Timeout!')
现在,你可以这样做:
t = Timeout(30)
for perm in permutations(x):
if isPrime(int(perm)):
large = perm
t.reset()
t.check()
如果你想使用自更新以来的循环次数而不是秒数,或者某些更高级的启发式算法,那就没那么复杂了。您只需要描述启发式,然后将其转换为代码。