leetcode322 零钱兑换 中等

给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例 1:

输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:

输入: coins = [2], amount = 3
输出: -1
说明:
你可以认为每种硬币的数量是无限的。

思路

方法1:
dfs+剪枝

class Solution {
private:
    int minsum;  
public:
    int coinChange(vector<int>& coins, int amount) {
        if(coins.empty()) return -1;
        sort(coins.begin(),coins.end());
        if(amount==0) return 0;
        if(amount<coins[0]) return -1;
        minsum=INT_MAX;
        int sum=0;
        dfs(coins,amount,sum,coins.size()-1);
        if(minsum==INT_MAX) return -1;
        return minsum;
    }
    void dfs(vector<int>& coins, int amount,int sum,int s){
        if(sum>=minsum||(sum+amount/coins[s]>=minsum)) return;//剪枝
        if(amount==0){
            minsum=min(minsum,sum);
            return;
        }
        for(int i=s;i>=0;--i){
            if(amount<coins[i]) continue;//剪枝
            dfs(coins,amount-coins[i],sum+1,i);
        }
    }
};

方法二:
首先尝试贪心算法:
面值【1,2,5,7,10】,金额14,贪心则每次优先使用大面值的金额,如先选10,还剩4,在选两张2,得到最优数量3,但是金额14只需要两张7即可,所以贪心是不可行的

动态规划:
dp[i] 代表的并不是第几张钞票面值(与结果无关,不能递推),而是金额i的最优解(最小使用张数),这样才能通过递推dp[i]来得到最终结果

现在我们在已知dp[i-1],dp[i-2],dp[1]的情况下,要递推出dp[i]。
而金额(状态) i 可由:
金额 i-1 与面值1的组合
金额 i-2 与面值2的组合
金额 i-5 与面值5的组合
金额 i-7 与面值7的组合
金额 i-10 与面值10的组合

这样,每次状态的转移只是多加了一张,能够保证每次状态的转移是增加了最少的数量的。而能够得到最优解的条件就是找出最小的前一个状态的数量。即dp[i] = min(dp[i-1],dp[i-2],dp[i-5],dp[i-7],dp[i-10])+1

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
          int INF = amount + 1;
          vector<int> dp(amount+1, INF);
          dp[0] = 0;
          for(int i=0;i<coins.size();i++){
              for(int j=coins[i];j<amount+1;j++){
                  dp[j]=min(dp[j],dp[j-coins[i]]+1);//状态转移方程
              }
          }
          return dp[amount]<INF?dp[amount]:-1;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值