算法课第14周第1题——322. Coin Change

本篇博客介绍如何使用动态规划解决322. Coin Change问题,该问题要求找出给定硬币面额无限供应的情况下,组成特定金额所需的最少硬币数。通过分析,将问题转化为可重复背包问题,列出转移方程并给出代码实现。
摘要由CSDN通过智能技术生成

题目描述:

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:
coins = [1, 2, 5], amount = 11
return 3 (11 = 5 + 5 + 1)

Example 2:
coins = [2], amount = 3
return -1.

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


程序代码:

class Solution {
public:
	int coinChange(vector<int>& coins, int amount) {
		// dp[j]表示总价值为j时,最少的硬币数量
		// dp[0]初始化为0,其余都初始化为最大整数值
		vector<int> dp(amount + 1, INT_MAX);
		dp[0] = 0;

		// 类似可重复背包,但每次比较取较小值
		// 注意需要判断dp[j-coins[i]] != INT_MAX,否则可能溢出
		for (int i = 0; i < coins.size(); i++) {
			for (int j = coins[i]; j <= amount; j++) {
				if (dp[j - coins[i]] != INT_MAX) {
					dp[j] = min(dp[j], dp[j - coins[i]] + 1);
				}
			}
		}

		// 若dp[amount] >= INT_MAX, 说明无法组合取得总价值为amount
		if (dp[amount] >= INT_MAX)
			return -1;
		else return  dp[amount];
	}
};


简要题解:

本题是一道有关动态规划的问题。

先理清题意。本题输入是一组硬币(这组硬币中每个面额都可以无限使用)和一个amount值,要求输出硬币总面额为amount值的最小硬币数量,若无法达到amount值,则输出-1.

一开始,我认为本题应该类似一般的背包问题,只不过有以下几点不同:初始化时除了dp[0]初始化为0以外,其他都初始化为INT_MAX(这是因为后面要比较取min值);需要将背包问题中每次取两个价值中的max值改为取min值;且需要将每个硬币的价值都看作1.

但仔细分析后发现,除了以上几点不同点之外,本题实际上还是一个可重复背包问题,因为每个面额的硬币都可以无限次取用。

分析过后,就可以列出转移方程了。类似于可重复背包问题,可以列出转移方程为:

先初始化dp[0] = 0. 其他dp中的值为INT_MAX

        外层循环枚举i = 0...到coins.size(),内层循环枚举j = coins[i] ...到amount (这里就是可重复背包与普通背包的主要不同之处,若是普通背包,则是从amount到coins[i]):

若dp[j - coins[i] ]不为INT_MAX(防止计算溢出),则dp[j] = min{dp[j], dp[j - coins[i]] + 1}  (表示从 j 的总面额中去掉一个coins[i]的面额,并相应加上价值1)

最后输出时,只需判断dp[amount]是否>= INT_MAX, 若是,则说明计算取min的过程中其没有取过dp[j - coins[i]] + 1,也就是说其没有取出过某个硬币coins[i]的面额,那么amount的总面额无法被硬币组合得到,则输出为-1; 若不是,则输出即为dp[amount].


本题巧妙地改造了可重复背包问题,是一道比较有意思的动态规划问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值