面试题 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
说明:

注意:

你可以假设:

0 <= n (总金额) <= 1000000

 

解答:

一两周没怎么刷题,中等题都要看题解了。。原来是一个完全背包问题,妈蛋看过阿,怎么没联想出来呢?

二维dp:

class Solution {
public:
    int waysToChange(int n) {
        vector<vector<int> >dp(4,vector<int>(n+1,0));
        vector<int> value={1,5,10,25};
        dp[0][0]=1;
        dp[1][0]=1;
        dp[2][0]=1;
        dp[3][0]=1;
        for(int i=0;i<4;++i){   //dp[i][j]:只用前i种硬币,达到j币值的方法数
            for(int j=1;j<=n;++j){
                if(i>0){
                    dp[i][j]+=dp[i-1][j];
                }
                if(j-value[i]>=0){
                    dp[i][j]+=dp[i][j-value[i]];
                }
                dp[i][j]%=1000000007;
            }
        }
        return dp[3][n];
    }
};

 

 

由于dp递推关系中dp[i][j]只需要用到dp[i-1][j]和dp[i][j-coins[i]],也就是只用到了上一行、当前列之前的结果。

那么可以优化dp数组到一维:

class Solution {
public:
    int waysToChange(int n) {
        vector<int>dp(n+1,0);
        vector<int> value={1,5,10,25};
        dp[0]=1;
        for(int i=0;i<4;++i){
            for(int j=value[i];j<=n;++j){
                dp[j]=(dp[j]+dp[j-value[i]])%1000000007;
            }
        }
        return dp[n];
    }
};

 

posted @ 2020-04-08 01:24  NeoZy  阅读(268)  评论(0)    收藏  举报