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)) # 9Coin 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])) # 1Combinaciones 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])) # 13Problema 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)) # 22Coin 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)) # -1Diferencia 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
- Mochila 0/1 y optimización del espacio
- Mochila ilimitada y Coin Change II
- Suma de subconjunto con partición igual
- Target Sum con signos positivos y negativos