在Python中递归求子集和
我很高兴能得到一些帮助。
我遇到了以下问题:
我有一个数字列表 seq
和一个目标数字,我需要写两个东西:
第一个是一个递归的解决方案,如果有某个子序列的和等于目标数字,就返回
True
,否则返回False
。 举个例子:subset_sum([-1,1,5,4],0) # True subset_sum([-1,1,5,4],-3) # False
第二个是基于我在第一个解决方案中写的内容,但这次要使用记忆化(memoization),也就是用一个字典来存储结果,字典的键是元组:
(len(seq),target)
对于第一个问题,这是我目前的进展:
def subset_sum(seq, target):
if target == 0:
return True
if seq[0] == target:
return True
if len(seq) > 1:
return subset_sum(seq[1:],target-seq[0]) or subset_sum(seq[1:],target)
return False
我不确定我做得对不对,所以如果能得到一些反馈,我会很感激。
对于第二个问题:
def subset_sum_mem(seq, target, mem=None ):
if not mem:
mem = {}
key=(len(seq),target)
if key not in mem:
if target == 0 or seq[0]==target:
mem[key] = True
if len(seq)>1:
mem[key] = subset_sum_mem(seq[1:],target-seq[0],mem) or subset_sum_mem(seq[1:],target,mem)
mem[key] = False
return mem[key]
我无法让记忆化给我正确的答案,所以我希望能得到一些指导。
感谢任何愿意提供帮助的人!
3 个回答
0
我有这段修改过的代码:
def subset_sum(seq, target):
left, right = seq[0], seq[1:]
return target in (0, left) or \
(bool(right) and (subset_sum(right, target - left) or subset_sum(right, target)))
def subset_sum_mem(seq, target, mem=None):
mem = mem or {}
key = (len(seq), target)
if key not in mem:
left, right = seq[0], seq[1:]
mem[key] = target in (0, left) or \
(bool(right) and (subset_sum_mem(right, target - left, mem) or subset_sum_mem(right, target, mem)))
return mem[key]
你能给我一些这个代码不适用的测试案例吗?
0
这是我写的 subset_sum
函数:
def subset_sum(seq, target):
if target == 0:
return True
for i in range(len(seq)):
if subset_sum(seq[:i] + seq[i+1:], target - seq[i]):
return True
return False
在几个例子上它运行得不错:
>>> subset_sum([-1,1,5,4], 0))
True
>>> subset_sum([-1,1,5,4], 10)
True
>>> subset_sum([-1,1,5,4], 4)
True
>>> subset_sum([-1,1,5,4], -3)
False
>>> subset_sum([-1,1,5,4], -4)
False
老实说,我不知道怎么用记忆化来优化它。
旧编辑:我把使用 any()
的解决方案删掉了,因为经过一些测试我发现那样反而更慢!
更新:出于好奇,你也可以使用 itertools.combinations
:
from itertools import combinations
def com_subset_sum(seq, target):
if target == 0 or target in seq:
return True
for r in range(2, len(seq)):
for subset in combinations(seq, r):
if sum(subset) == target:
return True
return False
在某些情况下,这种方法比动态规划的方式更好,但在其他情况下可能会卡住(不过总的来说,它比递归的方法要好)。
1
这里有一个使用动态规划的解决方案,供大家参考:
def positive_negative_sums(seq):
P, N = 0, 0
for e in seq:
if e >= 0:
P += e
else:
N += e
return P, N
def subset_sum(seq, s=0):
P, N = positive_negative_sums(seq)
if not seq or s < N or s > P:
return False
n, m = len(seq), P - N + 1
table = [[False] * m for x in xrange(n)]
table[0][seq[0]] = True
for i in xrange(1, n):
for j in xrange(N, P+1):
table[i][j] = seq[i] == j or table[i-1][j] or table[i-1][j-seq[i]]
return table[n-1][s]