背包问题-敲代码:lintcode-669-换最少的硬币(完全背包变种)

本文详细解析了Lintcode669换硬币问题,通过完全背包算法求解最少硬币数量,介绍了两种代码实现方式,深入理解状态转移方程及初始化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Lintcode 669. 换硬币

(1)题目描述

        给出不同面额的硬币以及一个总金额。写一个方法来计算给出的总金额可以换取的最少的硬币数量。如果已有硬币的任意组合均无法与总金额面额相等,那么返回 -1。你可以假设每种硬币均有无数个。

样例1

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

样例2

输入: 
[2]
3
输出: -1

(2)题解-敲代码

        每种硬币数量不限,可以看作完全背包。需要装满背包,是恰好背包。—— 完全恰好背包。

        一维完全恰好背包:(1) 初始化方式; (2)二层循环正序; (3)状态转移方程按01处理; (4)检查是否恰好装满;

        状态定义:

                    dp[ i ][ j ] —— 考虑到第i个物品时,所需要的最少硬币数。

        完全背包-状态转移方程:

        dp[j] = min(dp[j], dp[j-k*coins[i]] + k);     (k*coins[i] <= j)

        01背包-状态转移方程:

        dp[j] = min(dp[j], dp[j-coins[i]] + 1);     // 公式按01背包处理

代码一:

class Solution {
public:
    /**
     * @param coins: a list of integer
     * @param amount: a total amount of money amount
     * @return: the fewest number of coins that you need to make up
     */
    int coinChange(vector<int> &coins, int amount) {
        // write your code here
        if(amount == 0) return 0;
        int n = coins.size();
        if(n==0 && amount) return -1;

        // 一维dp,完全恰好背包
        vector<int> dp(amount+1, INT_MAX);  // 没有硬币,其他总金额所需最少硬币数为无穷大
        dp[0]=0;                            // 恰好背包,总金额0不需要硬币
        
        for(int i=0; i<n; i++)       // 硬币
        {
            for(int j=coins[i]; j<=amount; j++)    // 当前总金额,正序,完全背包解法,里面是01背包dp公式
            {
                if(dp[j-coins[i]] == INT_MAX) continue;     // 无穷大会溢出
                
                dp[j] = min(dp[j], dp[j-coins[i]] + 1);     // 公式按01背包处理
            }
        }
        
        if(dp[amount] == INT_MAX)   // 是否恰好装满
            return -1;
        else
            return dp[amount];
    }
};

代码二:将无穷大定义为 INT_MAX/2,这样可以继续加数,一般不会溢出

class Solution {
public:
    /**
     * @param coins: a list of integer
     * @param amount: a total amount of money amount
     * @return: the fewest number of coins that you need to make up
     */
    int coinChange(vector<int> &coins, int amount) {
        // write your code here
        if(amount == 0) return 0;
        int n = coins.size();
        if(n==0 && amount) return -1;

        // 一维dp,完全恰好背包
        vector<int> dp(amount+1, INT_MAX/2);  // 没有硬币,其他总金额所需最少硬币数为无穷大
        dp[0]=0;                            // 恰好背包,总金额0不需要硬币
        
        for(int i=0; i<n; i++)       // 硬币
        {
            for(int j=coins[i]; j<=amount; j++)    // 当前总金额,正序,完全背包解法,里面是01背包dp公式
            {
                //if(dp[j-coins[i]] == INT_MAX/2) continue;     // 不考虑无穷大会溢出
                
                dp[j] = min(dp[j], dp[j-coins[i]] + 1);     // 公式按01背包处理
            }
        }
        
        if(dp[amount] == INT_MAX/2)   // 是否恰好装满
            return -1;
        else
            return dp[amount];
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值