Give you an integer array coins
, representing coins of different denominations; and an integer amount
, representing the total amount.
minimum number of coins required to make up the total amount. If no coin combination can make up the total amount, return -1
.
You can think that the number of each coin is unlimited.
Example 1:
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
Example 3:
Input: coins = [1], amount = 0
Output: 0
Example 4:
Input: coins = [1], amount = 1
Output: 1
Example 5:
Input: coins = [1], amount = 2
Output: 2
Problem-solving ideas
Some people may think of the greedy method for this problem, and prefer to use coins with large denominations to collect it, but greedy cannot get the optimal solution. For example, the following example:
int[] coins = {1, 2, 5, 7, 10};
int amount = 14;
If you use the greedy method, you must first use 10
, and then you need two 2
. A total of 3
coins are needed. But in fact, you only need two coins with a 7
to make up the amount of 14
Therefore, this problem requires the idea of dynamic programming.
From the following table, you can see the idea of dynamic programming. For the amount of i
that needs to be pieced together, traverse the face value of the coin, find the coin with a face value lower than the amount, coins[j]
, and then check whether there is an optimal solution dp[i - coins[j]]
dp
array, and put all possible The situation is listed, just find the smallest one. The whole process starts from 1
and iterates continuously, and iterates to the required amount.
Amount | Circumstances that can be collected | Optimal solution |
---|---|---|
0 | - | 0 |
1 | 1 | 1 (Use a coin with a face value of 1) |
2 | 2 | 1 (use a coin with a face value of 2) |
3 | 1 + dp[2], 2 + dp[1] | 2 (both are optimal solutions) |
4 | 1 + dp[3], 2 + dp[2] | 2(2 + dp[2]) |
5 | 5 | 1 (Use a coin with a face value of 5) |
6 | 1 + dp[5], 2 + dp[4], 5 + dp[1] | 2 (1 + dp[5] or 5 + dp[1]) |
7 | 7 | 1 (Use a coin with a face value of 7) |
8 | 1 + dp[7], 2 + dp[6], 5 + dp[3], 7 + dp[1] | 2 (1 + dp[7] or 7 + dp[1]) |
9 | 1 + dp[8], 2 + dp[7], 5 + dp[4], 7 + dp[2] | 2 (2 + dp[7] or 7 + dp[2]) |
10 | 10 | 1 (Use a coin with a face value of 10) |
11 | 1 + dp[10], 2 + dp[9], 5 + dp[6], 7 + dp[4], 10 + dp[1] | 2 (1 + dp[10] or 10 + dp[1]) |
12 | 1 + dp[11], 2 + dp[10], 5 + dp[7], 7 + dp[5], 10 + dp[2] | 2 (2 + dp[10] or 5 + dp[7] or 7 + dp[5] or 10 + dp[2]) |
13 | 1 + dp[12], 2 + dp[11], 5 + dp[8], 7 + dp[6], 10 + dp[3] | 3 (both are optimal solutions) |
14 | 1 + dp[13], 2 + dp[12], 5 + dp[9], 7 + dp[7], 10 + dp[4] | 2(7 + dp[7]) |
Reference Code
import java.util.Arrays;
public class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1]; // 初始化 dp 数组,大小为 amount + 1
Arrays.fill(dp, -1); // 全部元素初始化为 -1
dp[0] = 0; // 金额 0 的最优解 dp[0]=0
// 依次计算 1 至 amount 的最优解
for (int i = 1; i <= amount; i++) {
// 对于每个金额 i ,遍历面值 coins 数组
for (int j = 0; j < coins.length; j++) {
// 需要拼凑的面额 i 比当前面值 coins[j] 大,且金额 i - coins[j] 有最优解
if (coins[j] <= i && dp[i - coins[j]] != -1) {
// 如果当前金额还未计算或者 dp[i] 比当前计算的值大
if (dp[i] == -1 || dp[i] > dp[i - coins[j]] + 1) {
dp[i] = dp[i - coins[j]] + 1; // 更新 dp[i]
}
}
}
}
return dp[amount]; // 返回金额 amount 的最优解 dp[amount]
}
}
You can see that the above code nested a lot of for
and if
statement blocks, I wrote an array method implementation in TypeScript:
function coinChange(coins: number[], amount: number) {
// 创建长度为 amount + 1 ,全部元素为 -1 的数组
const dp = Array.from(new Array(amount + 1), () => -1);
dp[0] = 0;
// 数组 forEach 只能从头开始迭代,不能从中间某个位置开始
// 这里还是只能用 for 循环
for (let i=1; i<=amount; i++) {
// 遍历所有面值计算方案
const schemes = coins
.filter(coin => (coin <= i) && (dp[i - coin] !== -1))
.map(coin => 1 + dp[i - coin]);
// 如果方案存在,则使用方案中的最小值
if (schemes.length) {
dp[i] = Math.min(...schemes);
}
}
return dp[amount];
}
Using the array method to get rid of afor
loop and twoif
judgments, the performance is definitely not as good as the original, but the semantics are improved, and it is easy to understand
Time complexity: O(M*N)
( M
is the amount of money, N
is the number of coins)
Space complexity: O(M)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。