Разбор задачи Coin Change с LeetCode: как найти минимальное количество монет для суммы. Полный код на Python, мемоизация, сложность O(N*Amount). Практикуйтесь!
Задача Coin Change — классика собеседований и отличный тренажёр для освоения динамического программирования. Вы научитесь распознавать подзадачи, использовать мемоизацию и писать эффективный код. Разберём пошагово: от грубой силы до оптимизации.
Дан массив номиналов монет coins[] и целое число amount — сумма, которую нужно набрать. Каждую монету можно использовать неограниченное количество раз. Верните минимальное количество монет, необходимое для получения суммы. Если это невозможно — верните -1.
Пример: coins = [1, 2, 5], amount = 11 → ответ 3 (5 + 5 + 1).
Интуитивно: для каждой суммы перебираем все монеты и рекурсивно ищем решение для остатка. Выбираем минимальное количество монет среди всех вариантов.
def coin_change_brute(coins, amount):
if amount == 0:
return 0
if amount < 0:
return float('inf')
min_coins = float('inf')
for coin in coins:
res = coin_change_brute(coins, amount - coin)
if res != float('inf'):
min_coins = min(min_coins, 1 + res)
return min_coins
Недостаток: экспоненциальная сложность — одни и те же подзадачи считаются многократно.
Замечаем, что ответ для конкретной суммы не меняется. Сохраним его в массиве dp и будем переиспользовать. Это и есть динамическое программирование сверху вниз (Top-Down DP).
dp[target] — минимальное количество монет для суммы target.
Для каждой монеты coin:
dp[target] = 1 + dp[target - coin]Берём минимум по всем монетам.
def coinChange(coins, amount):
# Инициализируем dp значением -1 (означает, что не вычислено)
dp = [-1] * (amount + 1)
def solve(target):
if target == 0:
return 0
if target < 0:
return float('inf')
if dp[target] != -1:
return dp[target]
min_coins = float('inf')
for coin in coins:
res = solve(target - coin)
if res != float('inf'):
min_coins = min(min_coins, 1 + res)
dp[target] = min_coins
return dp[target]
ans = solve(amount)
return -1 if ans == float('inf') else ans
Пусть coins = [1, 2, 5], amount = 11.
Рекурсивные вызовы:
Таблица dp:
dp[1] = 1
dp[2] = 1
dp[3] = 2
dp[4] = 2
dp[5] = 1
...
dp[11] = 3Каждое состояние вычисляется ровно один раз.
Освоив Coin Change, вы сможете решать множество похожих задач: Perfect Squares, Minimum Cost Climbing Stairs, Rod Cutting, Unbounded Knapsack. Попробуйте прямо сейчас:
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →