5

Sarò felice di ricevere aiuto.Somma sottoinsieme ricorsiva in Python

Ho il seguente problema:

sto dato un elenco di numeri seq e di un numero di destinazione e ho bisogno di scrivere 2 cose:

  1. Una soluzione ricorsiva che ritorna True se ci è una somma di una sottosequenza uguale al numero di destinazione e False in caso contrario. esempio:

    subset_sum([-1,1,5,4],0) # True 
    subset_sum([-1,1,5,4],-3) # False 
    
  2. In secondo luogo, ho bisogno di scrivere una soluzione che utilizza quello che ho scritto nel precedente soluzione ma ora con Memoizzazione che utilizza un dizionario in cui le chiavi sono tuple: (len(seq),target)

per il numero 1 questo è quello che ho avuto modo finora:

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 

Non sono sicuro che ho capito bene, quindi se potessi ricevere un contributo, te ne sarei grato.

Per il numero 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] 

non riesco a ottenere il Memoizzazione di darmi la risposta corretta in modo da sarei contento per alcune indicazioni qui.

Grazie per chiunque sia disposto ad aiutare!

+2

Qual è il motivo che non stai usando solo [ '@ memoize'] (http://wiki.python.org/moin/PythonDecoratorLibrary# Memoize)? –

+2

Probabilmente perché è compito di casa;) –

+4

Si prega di taggare come compiti a casa se questo è in realtà i compiti. Le persone aiuteranno ancora. È una buona forma e può aiutare le persone a capire da dove vieni. – istruble

risposta

0

ho questo codice modificato:

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] 

Potete fornire alcuni casi di test questo non funziona per?

+0

funziona benissimo! Grazie mille. per capire in profondità la soluzione, puoi spiegare cosa fa la linea di ritorno? return target in (0, left) o \ (bool (destra) e (subset_sum (right, target - left) o subset_sum (right, target))) – user1123417

+0

Se questo è compito, dovresti capire come funziona - - e come è identico al tuo codice originale. – hughdbrown

+0

L'unica cosa che non capisco è ciò che bool (a destra) dà alla soluzione. Puoi spiegare? – user1123417

0

Questo è il modo che avrei scritto il 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 

Ha funzionato su un paio di esempi:

>>> 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 

Per essere onesti non saprei come Memoize esso.

Vecchio Modifica: Ho rimosso la soluzione con any() perché dopo alcuni test ho scoperto che per essere più lento!

Update: Solo per curiosità si potrebbe anche usare 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 

Questo può fare di meglio che l'approccio di programmazione dinamica, in alcuni casi, ma in altri si bloccherà (è comunque meglio allora il ricorsiva approccio).

+0

Vedrò grazie! – user1123417

+0

'subset_sum = lambda seq, target: (target == 0) o any (subset_sum (seq [: i] + seq [i + 1:], target - v) per i, v in enumerate (seq))' per noi masochisti;) Memoization è in realtà la ricerca di dizionario banale in questo caso. Bella soluzione! – stefan

+0

Oppure: 'return any (subset_sum (seq [: i] + seq [i + 1:], target - seq [i]) per i in range (len (seq)))' – hughdbrown

1

Solo per riferimento, ecco una soluzione con programmazione dinamica:

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] 
+0

Molto bello. Alternativa: 'def positive_negative_sums (seq): somma di ritorno (e per e in seq se e> = 0), somma (e per e in seq se e <0)' – hughdbrown

+0

(+1) Molto interessante, ho sicuramente imparato somthing! –