我正在尝试更快地解决子集求和问题的基本方法,我想出了这个
天真的方式是oldSS
函数,它测试所有2 ^ n个组合。但后来我注意到,在检查每个案例之前,计算当前场景可能的最小值和最大值,如果目标位于该范围的一侧,并且它可能是那里的解决方案,那么只有执行场景。这是newSS
函数。我正在测试时间,它给了我这个
9.91289400371
0.00154754789233
我可以通过将getMinMax
值缓存到全局变量中来进一步改善newSS时间。然而,对于天真的方法,使用聪明的hack将时间提高到2 ^(n / 2),将初始列表减少2然后对每个进行简单的方法,然后比较两个生成的列表。
但与2 ^(n / 2)运行时间相比,是否有人知道newSS函数的效果如何?
由于
import timeit
from random import randint
def oldSS(lst, acc, target):
if lst:
return oldSS(lst[1:], acc+lst[0], target) or oldSS(lst[1:], acc, target)
return acc==target
def randomList():
l = []
for i in range(20):
l.append(randint(0,1000))
return l
def getMinMax(lst):
mi = 0
mx = 0
for i in lst:
if i < 0:
mi += i
elif i > 0:
mx += i
return (mi, mx)
def newSS(lst, acc, target):
if lst:
a = False
b = False
mimx = getMinMax(lst[1:])
nmi = acc+lst[0] + mimx[0]
nmx = acc+lst[0] + mimx[1]
if target >= nmi and target <= nmx:
a = newSS(lst[1:], acc+lst[0], target)
nmi = acc + mimx[0]
nmx = acc + mimx[1]
if target >= nmi and target <= nmx:
b = newSS(lst[1:], acc, target)
return a or b
return acc==target
if __name__ == '__main__':
print timeit.timeit('oldSS(randomList(), 0, 60)', number=10, setup="from __main__ import oldSS,randomList")
print timeit.timeit('newSS(randomList(), 0, 60)', number=10, setup="from __main__ import newSS,getMinMax,randomList")
答案 0 :(得分:2)
您的新方法被称为分支和绑定,并在算法和复杂性理论的研究中进行了非常详细的分析。
已知分支和界限会降低问题的最佳案例复杂性。然而最坏的情况永远不会改想想一下数字的集合,其中小计的下限和上限非常接近目标。在这种情况下,您无法修剪搜索空间中任何有意义的部分。平均而言,您可以显着改善运行时间。计算分支定界算法的精确平均大小写复杂度有点困难,因为分支定界方法对输入分布非常敏感。我的教育但有点生疏的猜测是你的新算法的复杂性不会低于O(2 ^ n / 2)。
如果您需要关于渐近计算复杂度的科学答案,我建议您做一些研究,或者您可以在CS stack exchange上提出问题。如果您只是想了解哪种方法更好,您可以设置经验性试验来比较它们。这样的试验将是最好的实用方法。