【算法练习】动态规划 leetcode Coin Change

题目链接:https://leetcode.com/problems/coin-change/

322. Coin Change

Medium

5399164Add to ListShare

You are given coins of different denominations and a total amount of money amount. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.

You may assume that you have an infinite number of each kind of coin.

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

Constraints:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 231 - 1
  • 0 <= amount <= 104

动态规划的思路有时候很难想,先从简单的问题出发,再去考虑更复杂的情况,是一个多步决策的过程。

两种思路:

第一种:dp数组,数组的长度为amount,数组下标表示金额,数组值表示金额所需最少硬币数。

状态转移方程为:

dp[i] = min(dp[i], dp[i - coins[j]] + 1);

另一种理解的角度:借鉴其他的blog->这实际上是一个完全背包问题,可以将amount看成是背包容量,而coins中的每个硬币对应一个商品,每种商品可以使用无数次。在这里我们先复习一下完全背包问题如何处理。我们可以定义函数dp(v)表示amountv的时候最少硬币个数,那么就得到这个表达式

  •  dp(i,v)=min(dp(i-1,v),dp(i,v-coins[i])+1)
  • dp(i,v)表示选择第i个硬币的时候得到amount为v的最少硬币数量;dp(i-1,v)表示选择第i-1个硬币的时候得到amount为v的最少硬币数量
  • dp(i,v-coins[i])表示选择第i个硬币的时候得到amount为v-coins[i]的最少硬币数量

如果将O ( N V ) 个状态看成是N 行V 列的数组,那么( i , v ) 位置的值由( i − 1 , v ) 和( i , v − w i )决定。如果此时只采用O ( V ) 的空间处理,

  • dp(v)=min_{i=0}^{n}(dp(v-coins[i])+1) ​
完全背包和Coin Change对比
完全背包  硬币兑换
背包容量     要得到的amount
物品的重量  硬币的面值
物品的价值  --
求背包容量下最大价值 求正好得到amount的最小硬币个数

 

dp初始化巧妙全部初始化为amount+1,也就是最大值,因为硬币面值最小为1,那么dp[amount]=amount<amount+1

代码:

#include <iostream>
#include <vector>
using namespace std;
int coinChange(vector<int>& coins, int amount){
    vector<int> dp(amount+1,amount+1); //初始化全部为最大
    dp[0]=0;
    for(int i=1;i<=amount;i++){
        for(int j=0;j<coins.size();j++){
            if(i-coins[j]>=0){
                if(dp[i]>dp[i-coins[j]]+1){
                    dp[i]=dp[i-coins[j]]+1;//更新dp[i]
                }
            }
        }
    }
    return dp[amount]==amount+1?-1:dp[amount];
}
int main(){
   vector<int> coins={1,2,5};
   cout<<coinChange(coins,11);
    return 0;
}

第二种定义的dp数组长度为硬币的种类数,需要得到dp数列公式。

完全背包问题:https://blog.csdn.net/qq_17550379/article/details/104953480

参考博客:

https://www.cnblogs.com/grandyang/p/5138186.html

https://blog.csdn.net/qq_32805671/article/details/86939810

猜你喜欢

转载自blog.csdn.net/weixin_40760678/article/details/109945515