Dado um conjunto de moedas e um valor alvo, encontre o número mínimo de moedas necessárias para somar o valor. Clássico problema de DP bottom-up.
Aqui o "problema" é formar um valor exato com moedas. A menor unidade é formar cada valor menor que o alvo. Se eu souber a resposta para todos os valores menores, posso derivar a do alvo.
Defino então um estado indexado pelo valor: para cada j de 0 até amount, quanto custa formar j?
Coin Change é o exemplo canônico de Programação Dinâmica bottom-up. A ideia central: para resolver o valor j, basta saber a resposta dos valores menores. Se dp[j] = mínimo de moedas para formar j, então para cada moeda c disponível, uma forma de chegar em j é usar c como última moeda, vindo de j - c. Logo: dp[j] = min(dp[j - c] + 1) para toda moeda c ≤ j Resolvemos dp[0], dp[1], ..., dp[amount] em ordem crescente. Quando chegamos em dp[amount], já temos a resposta. Cada subproblema é resolvido uma única vez e reutilizado — daí o ganho sobre a recursão pura. Para reconstruir a combinação de moedas (não só o tamanho), guardamos em choice[j] qual moeda foi usada para atingir dp[j], e fazemos backtrack a partir de amount.
“A estrutura "subproblemas sobrepostos" é o que diferencia DP de divide-and-conquer. Mesmos subvalores são usados várias vezes — memoizá-los transforma uma recursão exponencial em algoritmo polinomial.”
n = valor alvo, m = número de moedas. Cada par (j, c) é processado uma vez.
Total de operações: amount × |coins| = n × m
Array dp de tamanho amount + 1. Se reconstruirmos a combinação, mais um array choice de mesmo tamanho.
DP bottom-up sempre preenche toda a tabela — não há atalho.
Mesma complexidade em qualquer entrada.
| Algoritmo | Tempo | Espaco | Melhor Para |
|---|---|---|---|
| Coin Change (DP)(atual) | O(n × m) | O(n) | Encontrar o mínimo garantido |
| Coin Change (Recursão Pura) | O(m^n) | O(n) | Didático — mostra a explosão exponencial sem DP |
| Coin Change (Guloso) | O(n log n) | O(1) | Só funciona para certos sistemas de moedas (como o brasileiro/euro) |
Pratique respondendo a perguntas comuns de entrevistas tecnicas. Clique em uma pergunta para iniciar uma sessao de pratica com IA.
1def coin_change(coins, amount):Definição2 INF = float('inf')3 dp = [INF] * (amount + 1)Inicialização do DP4 dp[0] = 05 choice = [None] * (amount + 1)6 7 for j in range(1, amount + 1):Loop de Valores8 for c in coins:Loop de Moedas9 if c <= j and dp[j - c] != INF:Validade10 candidate = dp[j - c] + 1Recorrência11 if candidate < dp[j]:12 dp[j] = candidate13 choice[j] = c14 15 if dp[amount] == INF:Resultado16 return -1, []17 18 # Backtrack para reconstruir as moedas19 coins_used = []20 j = amount21 while j > 0:22 coins_used.append(choice[j])23 j -= choice[j]24 25 return dp[amount], coins_used26