Mochila ilimitada e troco de moedas II
Permita reutilizar itens percorrendo a capacidade para a frente e resolva os problemas de troco de moedas II (contagem de formas) e corte de barras usando essa variante.
Mochila ilimitada e troco de moedas II é uma aula grátis de DSA Interview Prep no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de DSA Interview Prep, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de DSA Interview Prep inclui 4 aulas no total.
Conceito da mochila ilimitada
Na mochila ilimitada, cada item pode ser escolhido qualquer número de vezes (ao contrário da mochila 0/1, em que cada item é usado no máximo uma vez). A definição do estado é a mesma — dp[c] = valor máximo possível com capacidade c —, mas a direção do percurso muda. Como os itens podem ser reutilizados, ao atualizar dp[c] queremos permitir que o item atual seja usado novamente; por isso, percorremos a capacidade da esquerda para a direita (para frente).
A iteração para frente permite a reutilização
Na mochila 0/1, percorríamos a capacidade da direita para a esquerda para impedir a reutilização. Na mochila ilimitada, fazemos o oposto: percorremos da esquerda para a direita. Ao calcular dp[c], dp[c-w] já foi atualizado na passagem atual — o que significa que o item i possivelmente já foi incluído. É exatamente isso que queremos: o item i pode ser adicionado novamente a uma solução que já contém o item i.
def unbounded_knapsack(weights, values, W):
dp = [0] * (W + 1)
for i in range(len(weights)):
w, v = weights[i], values[i]
for c in range(w, W + 1): # iterate LEFT TO RIGHT
dp[c] = max(dp[c], dp[c - w] + v)
return dp[W]
weights = [1, 3, 4, 5]
values = [1, 4, 5, 7]
print(unbounded_knapsack(weights, values, 7)) # 9Troca de Moedas II: contar maneiras
A Troca de Moedas II pergunta: dadas as denominações das moedas e um valor, conte o número de maneiras distintas de obter esse valor (cada moeda pode ser usada um número ilimitado de vezes). Essa é uma variante da mochila ilimitada em que, em vez de maximizar o valor, contamos combinations. Defina dp[c] como o número de maneiras de obter o valor c. Caso base: dp[0] = 1 (há uma maneira de obter 0: não escolher nada).
Implementação da Troca de Moedas II
Para cada moeda, percorra os valores da esquerda para a direita e acumule: dp[c] += dp[c - coin]. O caso base dp[0] = 1 inicia a contagem. Observe que o laço externo percorre as moedas e o laço interno percorre os valores — isso produz naturalmente contagens de combinations (não de permutations), pois cada denominação de moeda é considerada exatamente uma vez como passagem externa.
def change(amount, coins):
dp = [0] * (amount + 1)
dp[0] = 1 # one way to make amount 0
for coin in coins:
for c in range(coin, amount + 1):
dp[c] += dp[c - coin]
return dp[amount]
print(change(5, [1, 2, 5])) # 4
print(change(3, [2])) # 0
print(change(10, [10])) # 1Combinações vs permutations
A ordem dos laços é fundamental. Se colocarmos o valor no laço externo e a moeda no laço interno, contaremos permutations (a ordem importa). Para amount=5 com as moedas [1,2], 1+2+2 e 2+1+2 serão contadas separadamente. Se colocarmos a moeda no laço externo, contaremos combinations (a ordem não importa): 1+2+2 e 2+1+2 serão a mesma. A Troca de Moedas II pede combinations, portanto a moeda fica no laço externo.
# Count COMBINATIONS (order does not matter) — coin outer loop
def combinations(amount, coins):
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins: # coin outer
for c in range(coin, amount + 1):
dp[c] += dp[c - coin]
return dp[amount]
# Count PERMUTATIONS (order matters) — amount outer loop
def permutations(amount, coins):
dp = [0] * (amount + 1)
dp[0] = 1
for c in range(1, amount + 1): # amount outer
for coin in coins:
if c >= coin:
dp[c] += dp[c - coin]
return dp[amount]
print(combinations(5, [1,2,5])) # 4
print(permutations(5, [1,2,5])) # 13Problema do corte de haste
Outro problema clássico de mochila ilimitada: dada uma haste de comprimento n e os preços para cada comprimento de haste de 1 a n, encontre a maior receita cortando a haste da melhor forma. Cada peça de comprimento l pode ser vendida por price[l], e as peças podem ser reutilizadas (a haste pode ser cortada em várias peças do mesmo comprimento). Isso corresponde diretamente à mochila ilimitada, com W = n e os diferentes comprimentos de corte como itens.
def rod_cutting(prices, n):
# prices[i] = price of rod of length i+1
dp = [0] * (n + 1)
for length in range(1, n + 1): # each cut length
price = prices[length - 1]
for c in range(length, n + 1):
dp[c] = max(dp[c], dp[c - length] + price)
return dp[n]
prices = [1, 5, 8, 9, 10, 17, 17, 20]
print(rod_cutting(prices, 8)) # 22Troca de Moedas I: número mínimo de moedas
A Troca de Moedas I (um problema diferente) pede o número mínimo de moedas necessário para obter um valor-alvo. Aqui, dp[c] = número mínimo de moedas para obter o valor c. Recorrência: dp[c] = min(dp[c], dp[c - coin] + 1). Inicialize todas as entradas com inf, exceto dp[0] = 0. Esse problema também é ilimitado (as moedas podem ser reutilizadas), portanto percorra os valores da esquerda para a direita. Retorne dp[amount] se for finito; caso contrário, -1.
def coinChange(coins, amount):
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for c in range(coin, amount + 1):
dp[c] = min(dp[c], dp[c - coin] + 1)
return dp[amount] if dp[amount] != float('inf') else -1
print(coinChange([1,5,6,9], 11)) # 2 (5+6 or other combos)
print(coinChange([2], 3)) # -1Diferença fundamental: máximo vs mínimo vs contagem
As três variantes da mochila ilimitada usam operações diferentes sobre dp[c-coin]: Maximizar o valor: dp[c] = max(dp[c], dp[c-w] + v); inicializar com 0. Minimizar o custo: dp[c] = min(dp[c], dp[c-coin] + 1); inicializar com inf, dp[0]=0. Contar maneiras: dp[c] += dp[c-coin]; inicializar com 0, dp[0]=1. Reconhecer qual variante se aplica é metade do caminho para resolver problemas de entrevista.
Complexidade e dicas para entrevistas
Todas as variantes da mochila ilimitada executam em O(n × W) de tempo e O(W) de espaço, em que n é o número de tipos de itens e W é o valor-alvo. Em problemas de moedas, n é o número de denominações de moedas. Em entrevistas, informe a variante (máximo/mínimo/contagem), escreva a DP 1D e deixe claro se o laço externo percorre as moedas ou o valor — os avaliadores sabem que essa distinção testa uma compreensão profunda de DP.
Identificando mochila ilimitada vs 0/1
Use estes sinais para identificar qual variante se aplica: reutilização ilimitada → ilimitada (percurso para frente); cada item exatamente uma vez → 0/1 (percurso para trás); o problema diz “qualquer número de vezes”, “suprimento infinito” ou “reutilização permitida” → ilimitada. Exemplos: troca de moedas, corte de haste, quebra de inteiro — todos são ilimitados. Soma de subconjuntos, partição, mochila 0/1 — 0/1. Errar essa identificação causa respostas incorretas difíceis de depurar.
Quebra de inteiro e outras variantes
Quebra de inteiro (LeetCode 343): divida um inteiro n em pelo menos 2 inteiros positivos para maximizar o produto entre eles. Essa é uma mochila ilimitada em que os “itens” são os inteiros de 2 a n-1. Defina dp[i] = produto máximo de inteiros cuja soma é i. Para cada item j de 2 a i, dp[i] = max(dp[i], max(j, dp[j]) * max(i-j, dp[i-j])). Isso mostra como o padrão ilimitado se generaliza para além do contexto de moedas.
def integerBreak(n):
dp = [0] * (n + 1)
dp[1] = 1
for i in range(2, n + 1):
for j in range(1, i):
dp[i] = max(dp[i], max(j, dp[j]) * max(i-j, dp[i-j]))
return dp[n]
print(integerBreak(10)) # 36 (3+3+4 = 3*3*4 = 36)Verificação rápida
Teste sua compreensão dos conceitos de Estruturas de Dados & Algoritmos — Preparação para Entrevistas de Programação apresentados nesta lição.
Recapitulação da lição
Nesta lição, você aprendeu: a mochila ilimitada percorre a capacidade da esquerda para a direita para permitir a reutilização dos itens, a Troca de Moedas II conta combinations colocando a moeda no laço externo e as três variantes — maximizar, minimizar e contar — diferem apenas na operação da DP e na inicialização. Em seguida, usaremos a mochila 0/1 para resolver o problema de Partição em Subconjuntos de Soma Igual.
Perguntas Frequentes
A aula “Mochila ilimitada e troco de moedas II” é grátis?
Sim — o texto completo de “Mochila ilimitada e troco de moedas II” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de DSA Interview Prep, atualize para CoddyKit PRO. O curso de DSA Interview Prep inclui 4 aulas no total.
O que vou aprender em “Mochila ilimitada e troco de moedas II”?
Permita reutilizar itens percorrendo a capacidade para a frente e resolva os problemas de troco de moedas II (contagem de formas) e corte de barras usando essa variante. Você pratica DSA Interview Prep com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar DSA Interview Prep?
Nenhuma experiência prévia é necessária. DSA Interview Prep no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.
Quanto tempo leva a aula “Mochila ilimitada e troco de moedas II”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de DSA Interview Prep?
Sim. Cada aula de DSA Interview Prep inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Mochila 0/1 e otimização de espaço
- Mochila ilimitada e troco de moedas II
- Soma de subconjunto com partição igual
- Soma-alvo com sinais positivos e negativos