面试题 08.11. 硬币 (Java)

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

思路I:二维数组

可以看成是两个数组(一个是硬币金额,一个是总金额),String其实也是数组。两个数组想到=>动态规划。

dp[i][j]表示遍历到硬币i,金额j时共有几种方法。

状态转移方程:如果不选择当前硬币i,那么有dp[i-1][j]种方法;如果选择,那么有dp[i][j-coins[i]]种方法。

class Solution {
    public int waysToChange(int n) {
        int[] coins = new int[4];
        coins[0] = 1;
        coins[1] = 5;
        coins[2] = 10;
        coins[3] = 25;
        int[][] dp = new int[4][n+1];
        for(int i = 0; i < n+1; i++){
            dp[0][i] = 1;
        }
        for(int i = 0; i < 4; i++){
            dp[i][0] = 1;
        }

        for(int i = 1; i < 4; i++){
            for(int j = 1; j <= n; j++){   
                if(j-coins[i] >= 0) {
                    dp[i][j] = (dp[i-1][j] + dp[i][j-coins[i]]) % 1000000007;
                } else {
                    dp[i][j] = dp[i-1][j];
                }
            }
        }
        
        return dp[3][n];
    }
}

思路II: 遍历到i,j时,只与上一行j位置的值有关,所以当前行可以复用上一行结果,从而精简成一维数组。

class Solution {
    public int waysToChange(int n) {
        int[] coins = new int[4];
        coins[0] = 1;
        coins[1] = 5;
        coins[2] = 10;
        coins[3] = 25;
        int[] dp = new int[n+1];
        for(int i = 0; i < n+1; i++){
            dp[i] = 1;
        }

        for(int i = 1; i < 4; i++){
            for(int j = 1; j <= n; j++){   
                if(j-coins[i] >= 0) {
                    dp[j] = (dp[j] + dp[j-coins[i]]) % 1000000007;
                } 
            }
        }
        
        return dp[n];
    }
}
原文地址:https://www.cnblogs.com/qionglouyuyu/p/13304272.html