518. Coin Change II
leetcode medium
Task
Вам дан целочисленный массив coins, представляющий монеты разных номиналов, и целое число amount, представляющее общую сумму денег.
Верните количество комбинаций, которые составляют эту сумму. Если эту сумму нельзя составить никакой комбинацией монет, верните 0.
Предположим, что у вас есть бесконечное количество каждой монеты.
Ответ гарантированно вписывается в знаковое 32-битное целое число.
Пример:
Input: amount = 5, coins = [1,2,5]
Output: 4
Explanation: there are four ways to make up the amount:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
C# solution
matched/originalpublic class Solution {
public int Change(int amount, int[] coins) {
int[,] memo = new int[coins.Length, amount + 1];
for (int i = 0; i < coins.Length; i++) {
for (int j = 0; j <= amount; j++) {
memo[i, j] = -1;
}
}
return NumberOfWays(0, amount, coins, memo);
}
private int NumberOfWays(int i, int amount, int[] coins, int[,] memo) {
if (amount == 0) return 1;
if (i == coins.Length) return 0;
if (memo[i, amount] != -1) return memo[i, amount];
if (coins[i] > amount) {
memo[i, amount] = NumberOfWays(i + 1, amount, coins, memo);
} else {
memo[i, amount] = NumberOfWays(i, amount - coins[i], coins, memo)
+ NumberOfWays(i + 1, amount, coins, memo);
}
return memo[i, amount];
}
}C++ solution
auto-draft, review before submit#include <bits/stdc++.h>
using namespace std;
// Auto-generated C++ draft from the C# solution. Review containers, LINQ and helper types before submit.
class Solution {
public:
public int Change(int amount, vector<int>& coins) {
int[,] memo = new int[coins.size(), amount + 1];
for (int i = 0; i < coins.size(); i++) {
for (int j = 0; j <= amount; j++) {
memo[i, j] = -1;
}
}
return NumberOfWays(0, amount, coins, memo);
}
private int NumberOfWays(int i, int amount, vector<int>& coins, int[,] memo) {
if (amount == 0) return 1;
if (i == coins.size()) return 0;
if (memo[i, amount] != -1) return memo[i, amount];
if (coins[i] > amount) {
memo[i, amount] = NumberOfWays(i + 1, amount, coins, memo);
} else {
memo[i, amount] = NumberOfWays(i, amount - coins[i], coins, memo)
+ NumberOfWays(i + 1, amount, coins, memo);
}
return memo[i, amount];
}
}Java solution
matched/originalclass Solution {
public int change(int amount, int[] coins) {
int[][] memo = new int[coins.length][amount + 1];
for (int i = 0; i < coins.length; i++) {
Arrays.fill(memo[i], -1);
}
return numberOfWays(0, amount, coins, memo);
}
private int numberOfWays(int i, int amount, int[] coins, int[][] memo) {
if (amount == 0) {
return 1;
}
if (i == coins.length) {
return 0;
}
if (memo[i][amount] != -1) {
return memo[i][amount];
}
if (coins[i] > amount) {
memo[i][amount] = numberOfWays(i + 1, amount, coins, memo);
} else {
memo[i][amount] = numberOfWays(i, amount - coins[i], coins, memo) + numberOfWays(i + 1, amount, coins, memo);
}
return memo[i][amount];
}
}JavaScript solution
matched/originalvar change = function(amount, coins) {
const memo = Array.from({ length: coins.length }, () => Array(amount + 1).fill(-1));
const numberOfWays = (i, amount) => {
if (amount === 0) return 1;
if (i === coins.length) return 0;
if (memo[i][amount] !== -1) return memo[i][amount];
if (coins[i] > amount) {
memo[i][amount] = numberOfWays(i + 1, amount);
} else {
memo[i][amount] = numberOfWays(i, amount - coins[i]) + numberOfWays(i + 1, amount);
}
return memo[i][amount];
};
return numberOfWays(0, amount);
};Python solution
matched/originalclass Solution:
def change(self, amount: int, coins: List[int]) -> int:
def numberOfWays(i: int, amount: int) -> int:
if amount == 0:
return 1
if i == len(coins):
return 0
if memo[i][amount] != -1:
return memo[i][amount]
if coins[i] > amount:
memo[i][amount] = numberOfWays(i + 1, amount)
else:
memo[i][amount] = numberOfWays(i, amount - coins[i]) + numberOfWays(i + 1, amount)
return memo[i][amount]
memo = [[-1] * (amount + 1) for _ in range(len(coins))]
return numberOfWays(0, amount)Go solution
matched/originalfunc change(amount int, coins []int) int {
memo := make([][]int, len(coins))
for i := range coins {
memo[i] = make([]int, amount + 1)
for j := range memo[i] {
memo[i][j] = -1
}
}
var numberOfWays func(i, amount int) int
numberOfWays = func(i, amount int) int {
if amount == 0 {
return 1
}
if i == len(coins) {
return 0
}
if memo[i][amount] != -1 {
return memo[i][amount]
}
if coins[i] > amount {
memo[i][amount] = numberOfWays(i + 1, amount)
} else {
memo[i][amount] = numberOfWays(i, amount - coins[i]) + numberOfWays(i + 1, amount)
}
return memo[i][amount]
}
return numberOfWays(0, amount)
}Explanation
Algorithm
Создайте двумерный массив memo с n строками и amount + 1 столбцами. Инициализируйте значения -1, чтобы указать, что подзадача еще не решена. Реализуйте рекурсивный метод numberOfWays, который принимает два параметра: индекс i текущей рассматриваемой монеты и оставшуюся сумму, которую нужно составить. Он возвращает количество способов составить сумму, используя монеты, начиная с индекса i до последней монеты.
Если amount == 0, верните 1. Мы можем выбрать один способ, не выбирая ни одной монеты, чтобы составить сумму 0. Если i == n, у нас не осталось монет для составления суммы, верните 0. Если эта подзадача уже решена, т.е. memo[i][amount] != -1, верните memo[i][amount]. Если значение текущей монеты превышает сумму, мы не можем её использовать. Рекурсивно вызовите numberOfWays(i + 1, amount), присвойте результат memo[i][amount] и верните его.
В противном случае, добавьте общее количество способов составить сумму, как выбирая текущую монету, так и игнорируя её. Сложите значения numberOfWays(i, amount - coins[i]) и numberOfWays(i + 1, amount), сохраните результат в memo[i][amount] и верните его. Верните numberOfWays(0, amount), ответ на исходную задачу.
😎