题目地址:
https://leetcode-cn.com/problems/coin-change/
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 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/coin-change 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
class Solution { public: int coinChange(vector<int>& coins, int amount) { } };
class Solution { public: int coinChange(vector<int>& coins, int amount) { int MAX = amount+1;//确定好零钱最大个数 vector<int> dp(amount+1, MAX);//申请amount+1个空间,都赋值为MAX dp[0] = 0; for(int i=1;i<=amount;i++) { for(int j=0;j<coins.size();j++) { if(coins[j]<=i) // 硬币值小于当前的金额 { dp[i] = min(dp[i], dp[i-coins[j]]+1); //核心的状态转移方程 } } } return dp[amount]>amount ? -1:dp[amount]; } };
例如:
coins[1,2,5]
amount=11
dp[11]=MAX=amount+1
先构造一个dp数组,长度是amount+1,给每个元素赋值为 最大值。这里可以设定这个最大值为 amount+1。
再赋初值,设置dp[0]=0,表示amount为0的时候,需要的硬币个数为零。
dp[]数组解释:
这里的dp[]数组存的就是每个金额对应的最少硬币数。存的就是最终的解。
比如dp[6]=X,表示 总金额为6的时候,需要X个硬币。
dp[]数组是不断往后确定下去的,直到amount位置。
看下图,每一列的dp[],当amount=X的时候,dp[X]的值就确定了下来。
比如,amount=1的时候,dp[1]就确定了,此时dp[2]、dp[3]等等还是初始的最大值,是未确定的。
amount=2的时候,dp[2]就确定了,此时dp[3]、dp[4]等等还是初始的最大值,是未确定的。
这些已经确定下来的dp值,在amount 继续变大的时候,这些值是不会再变的。
比如amount=5, dp[1]依然是1,所以你会看到每一列的颜色不同,但是值是固定下来的。
dp[1]表示的仅仅是amount=1的时候,最小硬币数。
一定要动手一步一步推导一下,这样才能加深印象。否则,今天看懂了,过了2天,又忘记怎么写了。
手动一步一步推导,深入到细节,理解会更深刻。
分析步骤如下:
初始值,amount = 0:
dp[0] = 0,表示 总金额为0的时候,需要0个硬币。
牢记状态转移方程: dp[i] = min(dp[i], dp[i-coins[j]]+1); //核心的状态转移方程
我们一步一步来 推导、分析:
amount=1
dp[1] 为 MAX
for循环遍历coins硬币数组
dp[1 - 1] =dp[0]=0
根据状态转移方程,dp[1] = 1
amount=2
dp[2]为 MAX
for循环遍历coins硬币数组
dp[2-1] = dp[1] = 1
dp[2 -2] =dp[0] =0
根据状态转移方程,dp[2] = 1
amount=3
dp[3]为 MAX
for循环遍历coins硬币数组
dp[3-1] = dp[2] = 1
dp[3 -2] =dp[1] =1
根据状态转移方程,dp[3] = 2
amount=4
dp[4]为 MAX
for循环遍历coins硬币数组
dp[4-1] = dp[3] = 3
dp[4 -2] =dp[2] =1
根据状态转移方程,dp[4] = 2 (很多人以为这里会是3哦,其实是2)
amount=5
dp[5]为 MAX
for循环遍历coins硬币数组
dp[5-1] = dp[4] = 2
dp[5 -2] = dp[3] = 2
dp[5-5] = dp[0] = 0
根据状态转移方程,dp[5] = 1
amount=6
dp[6]为 MAX
for循环遍历coins硬币数组
dp[6-1] = dp[5] = 1
dp[6 -2] = dp[4] = 2
dp[6-5] = dp[1] = 1
根据状态转移方程,dp[6] = 2
amount=7
dp[7]为 MAX
for循环遍历coins硬币数组
dp[7-1] = dp[6] = 2
dp[7 -2] = dp[5] = 1
dp[7-5] = dp[2] = 1
根据状态转移方程,dp[7] = 2
amount=8
dp[8]为 MAX
for循环遍历coins硬币数组
dp[8-1] = dp[7] = 2
dp[8 -2] = dp[6] = 2
dp[8-5] = dp[3] = 2
根据状态转移方程,dp[8] = 3
amount=9
dp[9]为 MAX
for循环遍历coins硬币数组
dp[9-1] = dp[8] = 3
dp[9 -2] = dp[7] = 2
dp[9-5] = dp[4] = 2
根据状态转移方程,dp[9] = 3
amount=10
dp[10]为 MAX
for循环遍历coins硬币数组
dp[10-1] = dp[9] = 3
dp[10 -2] = dp[8] = 3
dp[10-5] = dp[5] = 1
根据状态转移方程,dp[10] = 2
amount=11
dp[11]为 MAX
for循环遍历coins硬币数组
dp[11- 1] = dp[10] = 2
dp[11 -2] = dp[9] = 3
dp[11 - 5] = dp[6] = 2
根据状态转移方程,dp[11] = 3