【LeetCode & 剑指offer刷题】动态规划与贪婪法题13:Coin Change(系列)

【LeetCode & 剑指offer 刷题笔记】目录(持续更新中...)

Coin Change(系列)

Coin Change
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.
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
Note:
You may assume that you have an infinite number of each kind of coin.

C++
 
//问题:硬币问题
/*
* 方法一:动态规划-带备忘机制的自顶向下法(较慢)
* 问题分解:C(amount)=C(amount−coin)+1,C(amount)表示凑成数量 amount所需的最少硬币数,(amount-coin)表示去除其中一个硬币coin。
* 分析:O(amount∗count),O(amount)
*/
/*
class Solution
{
public:
    int coinChange(vector<int>& coins, int amount)
    {
        if(amount < 1) return 0;
        vector<int> counter(amount); //创建计数器,初始化为0
        return coin_recur(coins, amount, counter);
    }
   
    int coin_recur(vector<int>& coins, int amount, vector<int>& counter)
    {
        if(amount < 0) return -1; //amount - coin有可能为负数
        if(amount == 0) return 0;
        if(counter[amount-1] != 0) return counter[amount-1]; //备忘机制
       
        int min_count = INT_MAX; //初始化最大数
        for(int coin:coins) //遍历coins中的coin,找到最小的C(amount-coin)
        {
            int count = coin_recur(coins, amount-coin, counter);
            if(count>=0 && count < min_count) min_count = count;
        }
        counter[amount-1] = (min_count == INT_MAX)? -1: min_count + 1; //这里amount-1是因为索引以0开始,如果min_count == MAX_INT 说明无法凑成amount,故赋值-1
       
        return counter[amount-1];
    }
};*/
/*
* 方法二:动态规划-自底向上法
dp[i]表示钱数为i时的最小硬币数,
 
递推式为:dp[i] = min(dp[i], dp[i - coins[j]] + 1);类似完全背包问题(硬币数不受限制,不同i时可以多次用到某个coin),剪绳子问题
遍历所有硬币,选择一个硬币使dp[i]最小
 
其中coins[j]为第j个硬币,而i - coins[j]为钱数i减去其中一个硬币的值,剩余的钱数在dp数组中找到值,然后加1和当前dp数组中的值做比较,取较小的那个更新dp数组。
 
* 例子:
    假设coins分别为1,2,3
    F(3) = min{F(3−c1),F(3−c2),F(3−c3)}+1
         = min{F(3−1),F(3−2),F(3−3)}+1
         = min{F(2),F(1),F(0)}+1
         = min{1,1,0}+1=1
*
*/
class Solution
{
public:
    int coinChange(vector<int>& coins, int amount)
    {
        if(amount < 1) return 0;
      
        vector<int> dp(amount+1, amount+1); //初始化为一较大数amount+1(对于整数硬币,amount的面值最多硬币数为amount,后面return语句会用到,判断是否能找零)
        dp[0] = 0;//假设dp[0] = 0,用作后面递推用
      
        for(int coin:coins) //先遍历硬币(此题也可以先遍历钱数)
        {
            for(int i = coin; i <= amount; i++) //遍历钱数,i=coin~amount 金额大于当前硬币时才进行更新 
            {
                dp[i] = min(dp[i], dp[i - coin] + 1); //遍历所有硬币,选择一个硬币使dp[i]最小
            }
        }
      
      
        return (dp[amount] > amount)? -1: dp[amount]; //不能找零时,返回-1
    }
};
518. Coin Change 2
518. Coin Change 2
You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin.
Note: You can assume that
  • 0 <= amount <= 5000
  • 1 <= coin <= 5000
  • the number of coins is less than 500
  • the answer is guaranteed to fit into signed 32-bit integer
Example 1:
Input: amount = 5, coins = [1, 2, 5]
Output: 4
Explanation: there are four ways to make up the amount:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
Example 2:
Input: amount = 3, coins = [2]
Output: 0
Explanation: the amount of 3 cannot be made up just with coins of 2.
Example 3:
Input: amount = 10, coins = [10]
Output: 1
 
/*
问题:硬币找零2(求找零方案数)
方法:动态规划(看的不是太懂)
dp[i][j]表示用前i个硬币组成钱数为j的不同组合方法
dp[i][j] = dp[i - 1][j] + (j >= coins[i - 1] ? dp[i][j - coins[i - 1]] : 0)
空间优化:
dp[i]表示组成钱数i的不同方法数
dp[i] = dp[i] + dp[i - coin] (i>coin时才加后面一项)
分别为选择coin或者不选择coin
*/
class Solution
{
public:
    int change(int amount, vector<int>& coins)
    {
        vector<int> dp(amount + 1, 0); //多分配空间,方便索引
        dp[0] = 1; //初始化为1,当式子中i=coin时可以将dp[i]赋值为1,表示使用此coin,方案数为1
       
        for (int coin : coins) //注意先遍历硬币
        {
            for (int i = coin; i <= amount; i++) //遍历钱数,i = coin~amout
            {
                dp[i] = dp[i] + dp[i - coin]; //前者对应不选择coin,使用之前的coin得到的方案数,后者对应选择当前coin的方案数
            }
        }
        return dp[amount];
    }
};
 
 

 

posted @ 2019-01-06 16:53  wikiwen  阅读(506)  评论(0编辑  收藏  举报