Python: рекурсивная функция. Как вернуть все подмножества targetsum

Мой код не показывает кратчайшее подмножество, например [7], или не читает все подмножества, [7], [3,4], чтобы вернуть кратчайшее подмножество. Можете объяснить, почему возвращается только 1 набор результатов и как мне изменить его, чтобы показать все подмножество? Спасибо

Изображение кода, которому я хотел следовать, как показано ниже


def howsum(targetsum,numbers,combo=None):
    
    if combo == None:
        combo = list()
    if targetsum == 0: return [ ]
    if targetsum < 0: return None
    shortcombo = None
    
    for number in numbers:
        remainder = targetsum - number      
        
        combo = howsum(remainder,numbers,combo)
        if combo != None:
            combo.append(number)
            if shortcombo == None or len(shortcombo) > len(combo):
                shortcombo = combo
                return shortcombo
                                    
    return shortcombo
     
print(howsum(7,[4,3,7]))

А вы пробовали отладку резиновых уточек? Попробуйте вручную пройтись по коду и посмотрите, придете ли вы к желаемому результату и как вы этого добьетесь. Должно быть довольно очевидно, где что-то происходит.

Green Cloak Guy 21.12.2020 06:24

[ссылка] youtu.be/oBt53YbR9Kk я пытался воспроизвести логику из этой ссылки на ютубе. Но я потерпел неудачу. Попробую почитать про отладку.

SoraHeart 21.12.2020 06:26
Почему в Python есть оператор &quot;pass&quot;?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python.
Некоторые методы, о которых вы не знали, что они существуют в Python.
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
2
871
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Я не уверен в этом, но при определении функции в python и предоставлении 2 наборов кодов фактически не выполняется второй набор кода при вызове функции. У меня такая же проблема с другим проектом. И я не получил ответов, кроме как сказать, что я сделал что-то не так в коде!!!

[ссылка] youtu.be/oBt53YbR9Kk я следовал коду из этого видео. Но я не могу получить тот же результат. Можете ли вы объяснить разницу?

SoraHeart 21.12.2020 06:30

Я проверил ваш код. Чего мне не хватало, так это

  • Неправильное размещение return и сохранение значений внутри комбо (set вместо списка).

     def howsum(targetsum,numbers,combo=None):
         if combo == None:
             combo = set()
         if targetsum == 0: 
             return [ ]
         if targetsum < 0: 
             return None
    
         for idx,number in enumerate(numbers):
             remainder = targetsum - number
             if howsum(remainder,numbers[idx:],combo) != None:
                 combo.add(number)
         else:
             return combo
         return None
    

print(howsum(7,[7,3,4,2,5]))

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

Привет, я попробовал код, который возвращает все возможные комбинации в наборе. Могу ли я узнать, как разделить его, например, на [3,4] и [7]?. Привет также, для чисел [2,6] он должен возвращать None. Я следил за этим видео на YouTube, но не могу повторить логику. [ссылка] youtube.com/watch?v=oBt53YbR9Kk&t=7613s. В видео используется список, эквивалентный Python? или это набор.

SoraHeart 21.12.2020 07:02

Добавлено запоминание, однако с 1 внутри наборов num. результаты пошли наперекосяк.

def best_sum(target_sum, numbers,memo=None):
    if memo == None:
      memo = dict()
    
    if target_sum in memo:
      return memo[target_sum]
  
    if target_sum == 0: return []
    if target_sum < 0: return None
    
    shortest_combination = None

    for num in numbers:
        remainder = target_sum - num
        remainder_combination = best_sum(remainder, numbers,memo)
        if remainder_combination != None:
            remainder_combination.append(num)
            combination = remainder_combination
            if shortest_combination == None or len(combination) < len(shortest_combination):
                shortest_combination = combination
    memo[target_sum] = shortest_combination
    return shortest_combination

print(best_sum(100,[5,1,25]))

Этот код по ответу, опубликованному DarylG, работает. Изменив .append на [*list,var] Однако я не понимаю, почему результат отличается между функцией append и *

def best_sum(target_sum, numbers,memo=None):
    if memo == None:
      memo = dict()
    
    if target_sum in memo:
      return memo[target_sum]
  
    if target_sum == 0: return []
    if target_sum < 0: return None
    
    shortest_combination = None

    for num in numbers:
        remainder = target_sum - num
        remainder_combination = best_sum(remainder, numbers,memo)
        if remainder_combination != None:
            combination = [*remainder_combination,num] #this line from append to *
            if shortest_combination == None or len(combination) < len(shortest_combination):
                shortest_combination = combination
    memo[target_sum] = shortest_combination
    return shortest_combination

print(best_sum(100,[5,1,25]))

@josephgan - Привет, Джозеф - для вашего тестового примера этот код не возвращает кратчайшее подмножество для вашего тестового примера. Он возвращает [4, 3], а не [7]. Я опубликую ответ, который точно соответствует коду JavaScript, который возвращает правильный результат.

DarrylG 21.12.2020 12:39

Привет, я скучаю, написал < на сравнении len. это должно быть len(shortcombo) > len(combo). Я прочитаю ваше решение с функцией *. не знал, что это использование также. Спасибо за помощь.

SoraHeart 22.12.2020 03:04

@josephgan - хороший улов. Вы должны обновить свой ответ с исправлением.

DarrylG 22.12.2020 03:13

Привет, Дэрри, я снова попытался реализовать мемоизацию с моим кодом. Однако, если число содержит 1 eg (100,[10,1,25]. С моим решением использовать append результаты пошли наперекосяк. Однако с использованием функции *. Он возвращает фактический результат. Не могли бы вы объяснить, почему? Однако без реализации мемоизации с 1 внутри числа мое решение не запуталось.

SoraHeart 22.12.2020 03:25

Привет Дэрил. Перепроверено. Решение для добавления не работает с огромным числом. Ничего общего с мемоизацией. Не уверен, почему.

SoraHeart 22.12.2020 04:05

@josephgan - я проголосовал за ваш ответ за всю проделанную вами работу. Простое исправление (которое может сказать вам, почему добавление не работает, состоит в том, чтобы вместо этого использовать: combination = remainder_combination + [num], что эквивалентно: combination = [*remainder_combination,num]. Проблема заключается в добавлении и запоминании, несколько решений в кеше заметок ссылаются на один и тот же массив. Когда вы добавляете к одному, вы добавляете их ко всем combination = remainder_combination + [num] создает отдельные массивы для решений, так что нет проблем.

DarrylG 22.12.2020 04:19
Ответ принят как подходящий

Написал код, полностью соответствующий исходному JavaScript.

Хотя имена JavaScript будут работать, я провел рефакторинг имен функций и переменных, чтобы они соответствовали стилю Python, а именно:

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

Код

def best_sum(target_sum, numbers):
    if target_sum == 0: return []
    if target_sum < 0: return None
    
    shortest_combination = None

    for num in numbers:
        remainder = target_sum - num
        remainder_combination = best_sum(remainder, numbers)
        if remainder_combination != None:
            combination = [*remainder_combination, num] # Python * equivalent to JavaSscript ...
            if shortest_combination == None or len(combination) < len(shortest_combination):
                shortest_combination = combination
    
    return shortest_combination

Тест

print(bestSum(7, [3, 4, 7])) # Output: [7]

Использование мемоизации (т. е. кэширования)

def best_sum(target_sum, numbers, memo = None):
    if memo is None:
        memo = {0:[]}
    if target_sum < 0:
        return None
    if target_sum in memo:
        return memo[target_sum]

    shortest_combination = None

    for num in numbers:
        remainder = target_sum - num

        remainder_combination = best_sum(remainder, numbers, memo)
        if remainder_combination != None:
            combination = [*remainder_combination, num] # Python * equivalent to JavaSscript ...
            if shortest_combination == None or len(combination) < len(shortest_combination):
                shortest_combination = combination

    memo[target_sum] = shortest_combination

    return memo[target_sum]

print(best_sum(7, [3, 4, 7]))  # Output: 7
# Following very slow on non-memoized version
print(best_sum(100,[10,1,25])) # Output: [25, 25, 25, 25]

Помимо использования memo/любой переменной для запоминания, вы можете использовать метод functools.lru_cache. Просто не забудьте ввести тип ввода во время тестирования.

import functools

@functools.lru_cache(maxsize=4)
def howsum(targetnum, num_list):
    if targetnum == 0:
        return []
    if targetnum < 0:
        return None
    for num in num_list:
        rem = targetnum - num
        rem_val = howsum(rem, num_list)
        if rem_val is not None:
            rem_val.append(num)
            return rem_val
    return None

print(howsum(7, tuple([5, 3, 4, 7])))
print(howsum(8, tuple([3, 4, 2])))
print(howsum(300, tuple([7, 14])))

Другие вопросы по теме