python求列表中数字和_python – 一个列表中找到哪个数字的算法,总和到一定数量...

这个问题减少到

0-1 Knapsack Problem,在那里你试图找到一个精确的总和.解决方案取决于约束,在一般情况下,这个问题是NP-Complete.

但是,如果最大搜索总和(我们称之为S)不是太高,那么可以使用动态编程来解决问题.我将使用递归函数和memoization来解释它,这比自下而上的方法更容易理解.

我们来编写一个函数f(v,i,S),使得它返回v [i:]中与S精确匹配的子集数.为了递归地解决它,首先我们必须分析基数(即:v [我:]是空的)

> S == 0:[]的唯一子集具有和0,因此它是有效的子集.因此,函数应返回1.

> S!= 0:由于[]的唯一子集具有和0,所以没有有效的子集.因此,函数应返回0.

然后,我们分析递归的情况(即:v [i:]不为空).有两个选择:包括当前子集中的数字v [i],或不包括它.如果我们包含v [i],那么我们正在查找具有和S – v [i]的子集,否则我们仍然在寻找具有和S的子集.函数f可以以下列方式实现:

def f(v, i, S):

if i >= len(v): return 1 if S == 0 else 0

count = f(v, i + 1, S)

count += f(v, i + 1, S - v[i])

return count

v = [1, 2, 3, 10]

sum = 12

print(f(v, 0, sum))

通过检查f(v,0,S)> 0,你可以知道是否有解决你的问题.然而,这个代码太慢,每个递归调用产生了两个新的调用,这导致了一个O(2 ^ n)算法.现在,我们可以应用memoization使其运行在时间O(n * S),如果S不是太大,速度更快:

def f(v, i, S, memo):

if i >= len(v): return 1 if S == 0 else 0

if (i, S) not in memo: # <-- Check if value has not been calculated.

count = f(v, i + 1, S, memo)

count += f(v, i + 1, S - v[i], memo)

memo[(i, S)] = count # <-- Memoize calculated result.

return memo[(i, S)] # <-- Return memoized value.

v = [1, 2, 3, 10]

sum = 12

memo = dict()

print(f(v, 0, sum, memo))

现在可以对一个函数g进行编码,该函数返回一个求和S的子集.为此,仅当至少包含一个解决方案时才添加元素:

def f(v, i, S, memo):

# ... same as before ...

def g(v, S, memo):

subset = []

for i, x in enumerate(v):

# Check if there is still a solution if we include v[i]

if f(v, i + 1, S - x, memo) > 0:

subset.append(x)

S -= x

return subset

v = [1, 2, 3, 10]

sum = 12

memo = dict()

if f(v, 0, sum, memo) == 0: print("There are no valid subsets.")

else: print(g(v, sum, memo))

免责声明:这个解决方案说,有[10,10]的两个子集合总和10.这是因为它假设前十个与第二个十不同.该算法可以被固定为假定两者都相等(因此回答一个),但是这更复杂一些.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值