Подмножество суммы рекурсивно в Python - PullRequest
5 голосов
/ 26 января 2012

Я буду рад получить помощь.

У меня следующая проблема:

Мне дан список чисел seq и целевое число, и мне нужно написать 2 вещи:

  1. Рекурсивное решение, которое возвращает True, если существует сумма подпоследовательности, равная целевому числу, и False в противном случае. Пример:

    subset_sum([-1,1,5,4],0)   # True
    subset_sum([-1,1,5,4],-3)  # False
    
  2. Во-вторых, мне нужно написать решение, используя то, что я написал в предыдущем решении но теперь с мемоизацией, которая использует словарь, в котором ключи являются кортежами: (len(seq),target)

Для номера 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 ]

1 голос
/ 27 января 2012

Только для справки, вот решение с использованием динамического программирования:

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 голосов
/ 27 января 2012

Вот как я бы написал: 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

Если честно, я бы не знал, какчтобы запомнить его.

Old Edit: Я удалил решение с помощью 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

Это может быть лучше, чем подход динамического программирования в некоторых случаях, но в других он зависает (этов любом случае лучше, чем рекурсивный подход).

0 голосов
/ 27 января 2012

У меня есть этот модифицированный код:

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]

Можете ли вы предоставить несколько тестовых случаев, для которых это не работает?

...