Dadas monedas de diferentes denominaciones
coins
y un monto totalamount
. Escribe una función para calcular las monedas que pueden formar la cantidad total组合数
. Suponga que hay infinitas monedas de cada denominación.
Esta pregunta es 0-1
una variante del problema de la mochila, que es un problema de mochila completo, entonces, ¿qué es un problema de mochila completo?
Repasemos de nuevo el problema de la mochila 0-1 : le damos una W
mochila y N
artículos (cada artículo es diferente) que se pueden cargar con un peso de 1 , y cada artículo tiene dos atributos: peso y valor. i
El peso de la primer artículo es wt[i]
y el valor está val[i]
. Ahora le permiten usar esta mochila para empacar el artículo, ¿cuál es el valor máximo que se puede cargar?
0-1
El número de artículos en el problema de la mochila es limitado. Para ser precisos, cada artículo es único y hay monedas ilimitadas de cada denominación aquí. Es decir 完全背包问题
, la idea es la misma que la de la mochila 0-1, pero el estado la ecuación de transición cambia ligeramente.
Podemos 0-1
solucionar este problema según la idea de mochila :
Comparamos monedas de diferentes denominaciones con 0-1
artículos en el problema de la mochila, y comparamos la cantidad total con la capacidad de la mochila, de modo que se pueda transformar en un modelo de problema de mochila para su solución.
- El primer paso: borrar "estado" y "elección"
Hay dos estados, a saber, "la capacidad de la mochila" y "elementos opcionales", la opción es "empacar en la mochila" o "no en la mochila".
for 状态1 in 状态1的所有取值:
for 状态2 in 状态2的所有取值:
for ...
dp[状态1][状态2][...] = 计算(选择1,选择2...)
- Definición clara de matriz
dp
dp[i][j]
Se define de la siguiente manera: solo los i
dos primeros artículos, cuando la capacidad de la mochila j
cuando hay dp[i][j]
formas de llenar la mochila.
La conversión a un modelo de cambiador de monedas es: use solo coins
el i
valor nominal de las monedas del frente, si desea la cantidad de Couchu j
, hay dp[i][j]
tipos de métodos de error.
El caso base es dp[0][..] = 0, dp[..][0] = 1
. Porque si no usa el valor nominal de ninguna moneda, no puede recuperar ninguna cantidad, si la cantidad objetivo es 0, entonces "gobernar sin hacer nada" es la única forma de compensar.
Nuestro objetivo final es encontrar dp[N][amount]
, cuál N
es el coins
tamaño de la matriz.
- Según "elección", piense en la lógica de la transición de estado
Si no utiliza coins[i]
el valor nominal de la moneda, entonces la denominación de Couchu debe ser de j
varios métodos dp[i][j]
iguales dp[i-1][j]
, heredado los resultados anteriores.
Si usa coins[i]
el valor nominal de la moneda, dp[i][j]
debería ser igual dp[i][j-coins[i-1]]
.
Primero, como i
es desde el principio, coins
el índice es el i-1
tiempo que representa el i
valor nominal de las monedas.
dp[i][j-coins[i-1]]
No es difícil entender que si decides usar esta moneda, debes prestar atención a cómo cobrar la cantidad j - coins[i-1]
.
En resumen, son dos opciones, y queremos preguntar por dp[i][j]
un "número total de especies y error", por lo que dp[i][j]
el valor debe ser mayor que la suma de los resultados de las dos opciones:
class Solution {
int change(int amount, int[] coins) {
int n = coins.length;
int[][] dp = amount int[n + 1][amount + 1];
for (int i = 0; i <= n; i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= amount; j++){
if (j - coins[i-1] >= 0){
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i-1]];
}else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[n][amount];
}
}
Además, podemos descubrir a través de la observación, dp
transferir la matriz y solo dp[i][..]
y dp[i-1][..]
relevantes:
Por lo tanto, el estado se puede comprimir para reducir aún más la complejidad espacial del algoritmo:
class Solution {
public int change(int amount, int[] coins) {
int n = coins.length;
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int i = 0; i < n; i++){
for (int j = 1; j <= amount; j++){
if (j - coins[i] >= 0){
dp[j] += dp[j-coins[i]];
}
}
}
return dp[amount];
}
}
Incluso puede hacer esto:
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
// j直接从coin开始,避免了j - coins[i] >= 0的判断
for (int j = coin; j <= amount; j++) {
dp[j] += dp[j - coin];
}
}
return dp[amount];
}
}
Complejidad de tiempo O (cantidad N *)
Complejidad espacial O (cantidad)