【中等】面试题 08.11-硬币

题目

硬币。给定数量不限的硬币,币值为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

解法

方法一:计算

解题思路

对于总价值n,当选择coin25个25面值硬币时,剩下rest=n-25*coin25就由剩下3种面值组成,当有coin10个10面值硬币时,剩下rest-10*coin10的价值就最多包含(rest-10*coin10)/5个5面值硬币,也就是(rest-10*coin10)/5+1种方法。

所以,当选择i个25面值硬币时,剩下的组成方法就是\(\sum_{a=0}^{coin10}(rest-10*a)/5+1\)

代码

class Solution {
public:
    int waysToChange(int n) {
        int coin25 = n/25;
        int res = 0;
        for(int i = coin25; i >= 0; --i){
            int rest = n-(i*25);
            int coin10 = rest / 10;
            res = (res + (long((rest)/5+1-coin10)*(coin10+1)%1000000007))%1000000007;
        }
        return res;
    }
};

方法二:动态规划

解题思路

思路1:直接分析

首先,如果硬币面值只有1的话,无论总价值多大,选取的方法一定只是1,因为每次只能选择面值为1的硬币,所以count[n]=count[n-1]=1;

如果新增一个5的硬币,当总价值n不大于5时,仍旧只能选择1的硬币,但是当不小于5时,如果手里已经有了n-5的硬币,那么除了保持全选1的方法之外,还可以直接拿一个面值为5的硬币,也就是说,如果总价为n-5时有t种方法,那么总价为n时,就新增了t种方法,对于其他的面值也是一样,如果新增面值为coin,那么状态转移方程即为count[n] = count[n] + count[n-coin]

思路2:动态规划套用

首先,找状态量,题目问什么什么就是状态,题目问的是4种硬币组成价值n的方法,包含三个物理量:硬币集合/价值/方法数,其中,方法数是优化方向,价值是有限有序状态,硬币集合也是有限有序状态,所以,想到使用硬币集合大小4*价值集合大小n的数组,也就是count[i][j]表示前i个硬币构成价值j的方法数

下一步寻找状态转移方程,首先执行搜索顺序一定是逐渐增加i后逐渐增加j,就是说对于任意count[i][j],count[0...i-1][0...n]和count[0...i][j]是已知的,所以如果已知count[i][j-coin[i]]以及coin[i],那么count[i][j]种方法除了已知的count[i-1][j]种方法之外,一定包含count[i][j-coin[i]]种方法,也就是count[i][j] = count[i-1][j] + count[i][j-coin[i]]

代码

class Solution {
public:
    int waysToChange(int n) {
        vector<int> count(n+1, 1); // 只有1时有一种拿法
        int coin[4] = {5,10,25};
        for(int i = 0; i < 3; ++i){
            for(int j = coin[i]; j < n+1; ++j){
                count[j] = (count[j]+count[j-coin[i]])%1000000007; // 新增了新的面值
            }
        }
        return count[n];
    }
};
posted @ 2020-04-23 13:30  陌良  阅读(217)  评论(0编辑  收藏  举报