322.零钱兑换
322.零钱兑换
题目
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
示例 1:
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1
示例 2:
输入:coins = [2], amount = 3
输出:-1
示例 3:
输入:coins = [1], amount = 0
输出:0
示例 4:
输入:coins = [1], amount = 1
输出:1
示例 5:
输入:coins = [1], amount = 2
输出:2
提示:
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104
通过次数304,786提交次数6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/coin-change
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题解
从一个数组中按一定的选取方式得到目标target,尝试将题目进行转化为背包问题。
数组中的元素可以重复选择,那么是一道完全背包问题。
背包的容量为amount,物品为coins[i],物品的重量为coins[i]
1.确定dp[j]数组及下标的含义
dp[j]表示凑齐背包j所需的最少的硬币个数为dp[j]
2.确定递推式
dp[j]可以如何推出?
当前物品为coins[i]
- 凑齐j-coins[i]的背包最少需要dp[j-coin[i]]个硬币;那么加上coins[i],凑齐j的背包需要dp[j-coin[i]]+1枚硬币
- 不放入当前coins[i],之前已经凑齐了j的背包需要dp[j]枚硬币
本题求最少的硬币数,那么dp[j]=Math.min(dp[j],dp[j-coin[i]]+1)
3.dp数组如何初始化
选择的时是最小的硬币数,i=0时
dp[0] = 0;
amount=0时,不需要硬币。
i≠0时,dp[i] = Integer.MAX_VALUE
4.确定遍历的顺序
这道题需要的是最少的硬币个数,且是一个完全背包的问题。
先从左到右遍历物品,再从左到右遍历背包。
for(int coin:coins){
for(int j=coin;j<=amount;j++){
dp[j]=Math.min(dp[j],dp[j-coin]+1);
}
}
5.举例推导dp数组
coins = [1, 2, 3], amount = 4
代码
class Solution {
public int coinChange(int[] coins, int amount) {
int [] dp = new int [amount+1];
dp[0] = 0;
//初始化为最大值
for(int i = 1;i<=amount;i++){
dp[i] = Integer.MAX_VALUE;
}
for(int coin:coins){
for(int j=coin;j<=amount;j++){
//当dp[j-coin]为初始化时,+1会溢出变成-xxxx,也就是最小值。它为初始值说明dp[j]只有一种选择方法,就是不放入coins[i]
if(dp[j-coin]!=Integer.MAX_VALUE){
dp[j]=Math.min(dp[j],dp[j-coin]+1);
}
}
}
return dp[amount] == Integer.MAX_VALUE? -1:dp[amount];
}
}