leetcode 322:零钱兑换
无限背包问题:
有N种物品和一个容量为V的背包,每种物品都有无限件可用,第i件物品消耗的容量为Ci,价值为Wi,求解放入哪些物品可以使得背包中总价值最大。
无限背包(完全背包)特点:物品种类为n个(每种物品数量无限)
题目描述:给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
解题步骤:看到这类题目第一想法就是采用贪心算法来求解。但是贪心算法也存在不足之处:
如果我们换一组钞票面值,比如 1, 5, 11,我们要凑出15的时候, 贪心策略就会出错:
15 = 11 * 1 + 1 * 4 (贪心策略)
15 = 5 * 3(正确策略)
由于贪心算法无法适用于所有面额的情况,我们采用动态规划的方法来求解
1、 状态定义:dp[i]表示凑出金额i所需要的最小硬币数量
2、 状态转移方程:dp[i] = min(dp[i],dp[i-coins[i]]+1) (i >= conins[i])
Conins[i]表示最后一枚硬币的面值数,将该硬币添加进去后,总金额数减少,并且硬币数量增加
3、 初始化:dp[0] = 0,其他dp[i] = amount+1;
4、 输出:dp[amount]
代码:
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp, amount+1);
dp[0] = 0;
for (int i = 1; i < dp.length; i++) {
for(int j = 0;j < coins.length;j++) {
if(i >= coins[j])
dp[i] = Math.min(dp[i], dp[i-coins[j]]+1);
}
}
System.out.println(Arrays.toString(dp));
if(dp[amount] > amount)
return -1;
return dp[amount];
}