0Pricing
DSA Interview Prep · Aula

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))  # 9

Troca 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]))        # 1

Combinaçõ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]))   # 13

Problema 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))  # 22

Troca 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))          # -1

Diferenç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

  1. Mochila 0/1 e otimização de espaço
  2. Mochila ilimitada e troco de moedas II
  3. Soma de subconjunto com partição igual
  4. Soma-alvo com sinais positivos e negativos
← Voltar para DSA Interview Prep