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分钱