Python中递归子集和

时间:2012-01-26 19:50:40

标签: python recursion dynamic-programming memoization subset-sum

我很乐意得到一些帮助。

我有以下问题:

我给出了一个数字列表seq和一个目标号码,我需要写两件事:

  1. 递归解决方案,如果子序列的总和等于目标数,则返回True,否则返回False。 例如:

    subset_sum([-1,1,5,4],0)   # True
    subset_sum([-1,1,5,4],-3)  # False
    
  2. 其次,我需要使用我在之前的解决方案中编写的内容编写解决方案 但现在使用memoization,它使用键是元组的字典: (len(seq),target)

  3. 对于数字1,这是我到目前为止所得到的:

    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
    

    不确定我是否正确,所以如果我能得到一些意见,我将不胜感激。

    对于2号:

    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 :(得分: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]

答案 1 :(得分: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]

你能提供一些不起作用的测试用例吗?

答案 2 :(得分: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

在某些情况下,动态编程方法可以做得更好,但在其他情况下它会挂起(无论如何比递归方法更好)。