零钱兑换II--动态规划思路解决相似问题

本文代码采用C++

0x01.问题

 给定不同面额的硬币和一个总金额。写出函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。 

输入示例:5  1 2  5

输出示例:4

解释:有四种方式可以凑成总金额

5=5   5=2+2+1   5=2+1+1+1   5=1+1+1+1+1

C++函数形式为       int change(int amount, vector<int>& coins) 

阅读本文之前,可以先参考:零钱兑换问题--探索动态规划的基本思想 

 0x02.分析问题

这是零钱兑换问题的升级版,我们来比较一下和之前的题目有什么差异,之前是求兑换到指定金额最少需要多少硬币,而这次是有多少种零钱组合可以兑换到指定的金额,一个求最小值,一个求组合数。

我们继续回想之前解决这个问题的思路,状态为dp[i]表示达到金额 i 最少需要的硬币数,状态转移方程为 DP[i]=min{DP[i],DP[i-coin]+1},思路就是金额要到 i ,我们可以假设先用掉一种零钱,然后看达到金额 i-coin 最少需要的硬币数,依次不断的迭代,把所有情况考虑完,找出里面所需硬币数最少的一个。

我们再来看这个问题,发现是不是很相似,他们的最终条件是一样的,就是一定数量的零钱兑换指定的金额,不过之前那个题中,重点考虑最少需要的硬币数,而这个题需要求出所有的组合数,事实上,在上个题的思路中,是已经考虑到了所有组合数的可能得,为什么呢?因为要求出最小的,肯定所有组合数都要考虑一遍,才能找出最小的呀,我们发现这两个题思路如此相像,那么我们可以通过改变上个题的某些特征,来完成这个问题。

扫描二维码关注公众号,回复: 10015914 查看本文章

首先,状态肯定要变,dp[i]应该表示,兑换金额 i 可能得硬币组合数。

其次状态转移方程,肯定不是求最小的了,而是累加,加什么呢?就是加用掉一个硬币后,达到那个金额的组合数,我们可以写出状态转移方程:

DP[I]+=DP[i-coin]

初始条件,dp[0]=1。

具体循环思路还是一样,外层循环每个金额,内层循环每种硬币。

0x03.代码--一维动态规划

int change(int amount, vector<int>& coins) {
	vector<int> dp(amount + 1, 0);
	dp[0] = 1;
	for (int coin : coins) {
		for (int a = coin; a < amount + 1; a++) {
			dp[a] += dp[a - coin];
		}
	}
	return dp[amount];
}

0x04.动态规划思路解决相似问题

  • 很多动态规划问题的模型都是非常经典的,所以有很多人就会在这些模型的基础上加以改变,就成了新的问题。
  • 面对这些看似新的问题,不要慌,只要能找出和以前解决过的问题的某些相似性,你就可以利用之前的动态规划的思路,加以改变,去解决新的问题。

如果本文对你有帮助,请分享给你的朋友吧!

ATFWUS  --Writing  By 2020--03--15

发布了126 篇原创文章 · 获赞 142 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/ATFWUS/article/details/104874780
今日推荐