Subset sum recursively in Python

user1123417 picture user1123417 · Jan 26, 2012 · Viewed 8.5k times · Source

I will be happy to get some help.

I have the following problem:

I'm given a list of numbers seq and a target number and I need to write 2 things:

  1. A recursive solution that returns True if there is a sum of a subsequence that equals the target number and False otherwise. example:

    subset_sum([-1,1,5,4],0)   # True
    subset_sum([-1,1,5,4],-3)  # False
    
  2. Secondly, I need to write a solution using what I wrote in the previous solution but now with memoization that uses a dictionary in which the keys are tuples: (len(seq),target)

For number 1 this is what I got to so far:

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

Not sure I got it right so if I could get some input I will be grateful.

For number 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]

I can't get the memoization to give me the correct answer so I'd be glad for some guidance here.

Thanks for anyone willing to help!

Answer

Óscar López picture Óscar López · Jan 26, 2012

Just for reference, here's a solution using dynamic programming:

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]