LeetCode 08.11硬币:Dynamic Programming(1)

LeetCode 08.11硬币思路记录

最近在集中做LeetCode上的动态规划类的问题。在做题(看题解)过程中,发现了很多有意思的思路和方法。在这里做个简单的总结和梳理:

硬币。给定数量不限的硬币,币值为25分、10分、5分和1分,编写代码计算n分有几种表示法。(结果可能会很大,你需要将结果模上1000000007)

示例1:
输入: n = 5
输出:2
解释: 有两种方式可以凑成总金额:
5=5
5=1+1+1+1+1

示例2:
输入: n = 10 输出:4 解释: 有四种方式可以凑成总金额:
10=10
10=5+5
10=5+1+1+1+1+1
10=1+1+1+1+1+1+1+1+1+1
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/coin-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

传统的完全背包问题不在此重述,因为它的解法已经被很多大佬解释的通透了,无需本菜在此搬弄,这篇文章只对这个硬币问题梳理思路。
首先容我展示此题AC代码:

class Solution {
    
    
public:
    //常量定义
    const int Mod = 1000000007;
    int waysToChange(int n) {
    
    
    	//枚举硬币集合,方便递推时取用
        vector<int> CoinSet = {
    
    1, 5, 10, 25};
        //递推奠基
        int DP[1000010] = {
    
    0};
        DP[0] = 1;
        
        //递推
        for(auto Coin : CoinSet)
            for(int k = Coin ; k <= n ; ++k)
                DP[k] = (DP[k] + DP[k - Coin]) % Mod;

		//返回结果
        return DP[n];
    }
};

下面对这段代码逐段解释:

1.递推奠基:
首先DP[k]的含义是,当硬币总价值为k时硬币组合的方案数(更确切地说,方案总数对Mod取模)
那么你可以想见,此题需要的返回结果一定是DP[n]。

下面是递归奠基部分的详解:
初始化时,一定要将所有方案数清零,表示此时还未开始递推。

DP[0] = 1;表示需要的总价值为0时,方案数为1(就是不给任何硬币)。
注意这里不是0
想象一下,有人向你要0分钱。你有什么对策吗?当然有,那就是什么都不做,也不用掏钱,这就是唯一正确的处理方法。

2.递推
外层循环 for(auto Coin : CoinSet),表示你手中当前唯一持有的硬币面值。

for(auto Coin : CoinSet)

内层循环 for(int k = Coin ; k <= n ; ++k)表示对硬币总面值为k的方案数进行逐层递推。

for(int k = Coin ; k <= n ; ++k)                                                                         

所以循环的意思很好理解了,因为我手里只有Coin面值的硬币,所以总面值为k-Coin时的方案数再凑上手里这枚Coin面值的硬币,就是一种新的方案。
为了让结果不溢出,我们在计算时直接取模,于是就有了这行代码:

DP[k] = (DP[k] + DP[k - Coin]) % Mod;

最终返回结果DP[n]即可

猜你喜欢

转载自blog.csdn.net/zzy980511/article/details/106825931