You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin.
Note: You can assume that
- 0 <= amount <= 5000
- 1 <= coin <= 5000
- the number of coins is less than 500
- the answer is guaranteed to fit into signed 32-bit integer
Example 1:
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
Example 2:
Input: amount = 3, coins = [2] Output: 0 Explanation: the amount of 3 cannot be made up just with coins of 2.
Example 3:
Input: amount = 10, coins = [10] Output: 1
給定一些不同面值的硬幣,和一個錢數。編寫函數計算要得到目標金額有多少種不同的硬幣組合方式。
322. Coin Change 的變形,322題是求最少能用幾個硬幣組成給的錢數,而這題求的是組成給定錢數總共有多少種不同的方法。
解法:動態規划DP, 建立dp數組,保存能到達當前amount的步數。逐個金額遍歷,看只用前i個金額能到達j的步數有多少,實現方法是累加起來dp[當前amount - 第i個金額],最后返回dp[amount]。
State: dp[i], 表示總額為i時的方案數
Function: dp[i] = Σdp[i - coins[j]], 表示總額為i時的方案數 = 總額為i-coins[j]的方案數的加和
Initialize: dp[0] = 1, 表示總額為0時方案數為1
Retrun: dp[n] or dp[-1]
Java:
public class Solution { public int change(int amount, int[] coins) { if (coins == null || coins.length == 0) { return amount == 0? 1: 0; } int[] dp = new int[amount + 1]; dp[0] = 1; for (int i = 0; i < coins.length; i ++) { for (int j = 1; j <= amount; j ++) { if (j >= coins[i]) { dp[j] += dp[j - coins[i]]; } } } return dp[amount]; } }
Python:
class Solution(object): def change(self, amount, coins): """ :type amount: int :type coins: List[int] :rtype: int """ dp = [0] * (amount + 1) dp[0] = 1 for c in coins: for x in range(c, amount + 1): dp[x] += dp[x - c] return dp[amount]
擴展思考:將上述代碼中的循環順序對調,即為求不同硬幣的排列數(Permutation)
class Solution(object): def change(self, amount, coins): """ :type amount: int :type coins: List[int] :rtype: int """ dp = [0] * (amount + 1) dp[0] = 1 for x in range(amount + 1): for c in coins: if c > x: continue dp[x] += dp[x - c] return dp[amount]
C++:
class Solution { public: int change(int amount, vector<int>& coins) { vector<int> dp(amount + 1, 0); dp[0] = 1; for (int coin : coins) { for (int i = coin; i <= amount; ++i) { dp[i] += dp[i - coin]; } } return dp[amount]; } };
類似題目:
[LeetCode] 322. Coin Change 硬幣找零
[CareerCup] 9.8 Represent N Cents 組成N分錢
All LeetCode Questions List 題目匯總