0Pricing
Coding Interview Prep · Lección

Mochila ilimitada y Coin Change II

Permita reutilizar los elementos recorriendo la capacidad hacia delante, y resuelva coin-change-II (contar formas) y rod-cutting con esta variante.

Mochila ilimitada y Coin Change II es una lección gratuita de Coding Interview Prep en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de Coding Interview Prep, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de Coding Interview Prep incluye 4 lecciones en total.

Concepto de mochila ilimitada

En la mochila ilimitada, cada ítem se puede seleccionar cualquier número de veces (a diferencia de la mochila 0/1, donde cada ítem se utiliza como máximo una vez). La definición del estado es la misma: dp[c] = valor máximo alcanzable con capacidad c; sin embargo, cambia la dirección de la iteración. Como los ítems se pueden reutilizar, al actualizar dp[c] queremos permitir que el ítem actual se vuelva a utilizar, por lo que iteramos sobre la capacidad de izquierda a derecha (hacia delante).

La iteración hacia delante permite reutilizar los ítems

Recuerde que en la mochila 0/1 iterábamos de derecha a izquierda para impedir la reutilización. En la mochila ilimitada hacemos lo contrario: iteramos de izquierda a derecha. Al calcular dp[c], dp[c-w] ya se ha actualizado en el paso actual; esto significa que el ítem i posiblemente ya se incluyó. Eso es exactamente lo que queremos: el ítem i se puede añadir de nuevo a una solución que ya contiene el ítem 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

Coin Change II: contar las formas

Coin Change II plantea lo siguiente: dadas las denominaciones de unas monedas y un importe, cuente el número de formas distintas de alcanzar dicho importe (cada moneda se puede utilizar un número ilimitado de veces). Se trata de una variante de la mochila ilimitada en la que, en lugar de maximizar el valor, contamos combinaciones. Defina dp[c] como el número de formas de obtener el importe c. Caso base: dp[0] = 1 (hay una forma de obtener 0: no seleccionar nada).

Implementación de Coin Change II

Para cada moneda, itere sobre los importes de izquierda a derecha y acumule: dp[c] += dp[c - coin]. El caso base dp[0] = 1 inicializa el recuento. Observe que el bucle externo recorre las monedas y el interno recorre los importes; esto produce de forma natural recuentos de combinaciones (no permutaciones), porque cada denominación de moneda se considera exactamente una vez en cada pasada 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

Combinaciones frente a permutaciones

El orden de los bucles es de vital importancia. Si colocamos el importe en el bucle externo y la moneda en el interno, contamos permutaciones (el orden importa). Para amount=5 con coins [1,2], 1+2+2 y 2+1+2 se cuentan por separado. Si colocamos la moneda en el bucle externo, contamos combinaciones (el orden no importa): 1+2+2 y 2+1+2 son lo mismo. Coin Change II solicita combinaciones, por lo que la moneda debe estar en el bucle 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 de cortar una varilla

Otro problema clásico de mochila ilimitada: dada una varilla de longitud n y los precios de cada longitud de varilla entre 1 y n, encuentre el ingreso máximo cortando la varilla de forma óptima. Cada pieza de longitud l se puede vender por price[l], y las piezas se pueden reutilizar (la varilla se puede cortar en varias piezas de la misma longitud). Esto se corresponde directamente con la mochila ilimitada, con W = n y los distintos tamaños de corte como ítems.

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

Coin Change I: mínimo número de monedas

Coin Change I (un problema diferente) solicita el número mínimo de monedas necesario para obtener un importe objetivo. Aquí dp[c] = número mínimo de monedas para obtener el importe c. Recurrencia: dp[c] = min(dp[c], dp[c - coin] + 1). Inicialice todas las entradas con inf, excepto dp[0] = 0. Este problema también es ilimitado (las monedas se pueden reutilizar), por lo que se debe iterar de izquierda a derecha. Devuelva dp[amount] si es finito; de lo contrario, -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

Diferencia clave: máximo frente a mínimo y recuento

Las tres variantes de mochila ilimitada utilizan operaciones diferentes sobre dp[c-coin]: Maximizar el valor: dp[c] = max(dp[c], dp[c-w] + v); inicializar con 0. Minimizar el coste: dp[c] = min(dp[c], dp[c-coin] + 1); inicializar con inf, dp[0]=0. Contar formas: dp[c] += dp[c-coin]; inicializar con 0, dp[0]=1. Reconocer qué variante corresponde es la mitad del trabajo en los problemas de entrevistas.

Complejidad y consejos para entrevistas

Todas las variantes de mochila ilimitada se ejecutan en tiempo O(n × W) y espacio O(W), donde n es el número de tipos de ítems y W es el importe objetivo. En los problemas de monedas, n es el número de denominaciones. En las entrevistas, indique la variante (máximo/mínimo/recuento), escriba la programación dinámica 1D y especifique claramente si el bucle externo recorre las monedas o el importe; los evaluadores saben que esta distinción pone a prueba una comprensión profunda de la programación dinámica.

Identificar la mochila ilimitada frente a la mochila 0/1

Utilice estas señales para identificar qué variante corresponde: reutilización ilimitada → ilimitada (iteración hacia delante); cada ítem exactamente una vez → 0/1 (iteración hacia atrás); si el problema indica «cualquier número de veces», «suministro infinito» o «se permite reutilizar» → ilimitada. Ejemplos: cambio de monedas, corte de varillas y separación de enteros; todos son problemas ilimitados. Subset sum, partition y mochila 0/1 son problemas 0/1. Equivocarse en esto provoca respuestas incorrectas difíciles de depurar.

Integer Break y otras variantes

Integer Break (LeetCode 343): divida un entero n en al menos 2 enteros positivos para maximizar su producto. Se trata de una mochila ilimitada en la que los «ítems» son los enteros del 2 al n-1. Defina dp[i] = producto máximo de enteros cuya suma es i. Para cada ítem j entre 2 e i, dp[i] = max(dp[i], max(j, dp[j]) * max(i-j, dp[i-j])). Esto muestra cómo el patrón de la mochila ilimitada se generaliza más allá del contexto de las monedas.

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)

Comprobación rápida

Compruebe su comprensión de los conceptos de Data Structures & Algorithms — Coding Interview Prep de esta lección.

Resumen de la lección

En esta lección ha aprendido: la mochila ilimitada itera sobre la capacidad de izquierda a derecha para permitir la reutilización de los ítems, Coin Change II cuenta combinaciones colocando la moneda en el bucle externo, y las tres variantes —maximizar, minimizar y contar— solo se diferencian en la operación y la inicialización de la programación dinámica. A continuación utilizaremos la mochila 0/1 para resolver Partition Equal Subset Sum.

Preguntas frecuentes

¿La lección «Mochila ilimitada y Coin Change II» es gratis?

Sí — el texto completo de «Mochila ilimitada y Coin Change II» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de Coding Interview Prep, actualiza a CoddyKit PRO. El curso de Coding Interview Prep incluye 4 lecciones en total.

¿Qué aprenderé en «Mochila ilimitada y Coin Change II»?

Permita reutilizar los elementos recorriendo la capacidad hacia delante, y resuelva coin-change-II (contar formas) y rod-cutting con esta variante. Practicas Coding Interview Prep con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar Coding Interview Prep?

No se requiere experiencia previa. Coding Interview Prep en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Mochila ilimitada y Coin Change II»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de Coding Interview Prep?

Sí. Cada lección de Coding Interview Prep incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Mochila 0/1 y optimización del espacio
  2. Mochila ilimitada y Coin Change II
  3. Suma de subconjunto con partición igual
  4. Target Sum con signos positivos y negativos
← Volver a Coding Interview Prep