强行背包
class Solution {
public int coinChange(int[] coins, int amount) {
//首先使用一个一维数组来缓存状态
int[] dp = new int[amount + 1];
//起始时默认使用前i中硬币凑不出,使用target + 1表示
Arrays.fill(dp,amount + 1);
//初始时的dp[0]表示的是使用0种硬币凑出amount为0,只有一种方式,也就是不使用就是使用0个硬币
dp[0] = 0;
//动态规划,对于每一种硬币使用我们关心的是它右集中方法凑出j,不断叠加
for(int coin : coins){
//对于每一个j我们想办法凑出来使用硬币个数最少的情况,由于j位置的赋值依赖于上一次赋值的元素所以再j赋值之前不能改变j之前元素的值,只能从右往左赋值
for(int j = amount;j >= 1;j--){
//遍历使用硬币的所有情况我们只选取记录下来使用硬币的数量最少的值
for(int k = 0;coin * k <= j ;k++){
//逐个增加使用货币的数量直到j < coin * k,时表示如果再增加货币就超出了不能再使用了
dp[j] = Math.min(dp[j - coin * k] + k,dp[j]);
}
}
}
return dp[amount] == amount + 1 ? -1 : dp[amount];
}
}
换一种更为人性化的动态规划
class Solution {
public int coinChange(int[] coins, int amount) {
//创建一维数组用于记录[0,amount]的集合所需要的最少货币
int[] dp = new int[amount + 1];
//dp[0]表示使用货币来表示0所需要的最少货币的数量,当然为0
//动态规划每一个i,i表示的时当前所需要使用coins来代表的总钱数,我们可以通过增加所有货币种类种的一种来求出最小使用货币的数量
for(int i = 1;i <= amount;i++){
dp[i] = amount + 1;
for(int num : coins){
if(num <= i){
dp[i] = Math.min(dp[i],dp[i - num] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}