leetcode:硬币构成(九)

240 阅读2分钟

题目:

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

示例:

输入: 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

题解:

动态规划解法:完全背包问题 

完全背包问题即不限定硬币的个数地去组合硬币达到指定的值。 这道题为求组合成指定数额有几种情况,我们设置 dp 数组: dp[k] 为组成k面额的硬币情况数。

这里的 dp[0] 的含义是:组成0的硬币种类数为 1,(没有硬币也是一种情况)
可以用于边界判断,作为完美能被一个硬币表示的情况为 1。即:

while k - coin == 0 :
	dp[k] += dp[k - coin];
	=>
	dp[k] += dp[0];

错误解!!!!:

class Solution {
    public int waysToChange(int n) {
        
        int[] dp = new int[n + 1];
        
        int[] coins = new int[]{1,5,10,25};
        
        
        //刚好可以用一个硬币凑成的情况,是一种情况
        // while i == coin :
        //dp[i] = dp[i - coin] => dp[0]
        dp[0] = 1;
        
        /**
        * dp方程:dp[i] += dp[i - coin];
        */
        
        for(int i = 1; i <= n; i++) {
            for(int coin: coins) {
                if(i - coin < 0) break;
                dp[i] = (dp[i] + dp[i - coin]) % 1000000007;
            }
        }
        
        return dp[n];
    }
}

这是因为硬币的顺序是与题解无关的,但是却被多算了一遍,具体情况:

前面5种情况数:dp[1,5] = [1,1,1,1,2];

coin = 1:
dp[6] += (dp[6 - coin] => dp[5] => 2);
即拿到coin(1)的情况有两种 :
	coin(1,1,1,1,1) + coin(1);
	coin(5) + coin(1);
	
coin = 5:
dp[6] += (dp[6 - coin] => dp[1] => 1);
即拿到coin(5)的情况有一种:
	coin(1) + coin(5);

正确解qaq:

class Solution {
    public int waysToChange(int n) {
        
        int[] dp = new int[n + 1];
        
        int[] coins = new int[]{1,5,10,25};
        
        
        //刚好可以用一个硬币凑成的情况,是一种情况
        // while i == coin :
        //dp[i] = dp[i - coin] => dp[0]
        dp[0] = 1;
        
        /**
        * dp方程:dp[i] += dp[i - coin];
        */
        
        for(int coin : coins) {
            for(int i = coin; i <= n; i++) {
                dp[i] = (dp[i] + dp[i - coin]) % 1000000007;
            }
        }
        
        return dp[n];
    }
}

这种情况要把硬币的排序影响情况去除掉:

coin = 1:
前面5种情况数:dp[1,5] = [1,1,1,1,1];

dp[6] += (dp[6 - coin] => dp[5] => 1);
即拿到coin(1)的情况有一种 :
	coin(1,1,1,1,1) + coin(1);
	
coin = 5:
前面5种情况数:dp[1,5] = [1,1,1,1,2];

dp[6] += (dp[6 - coin] => dp[1] => 1);
即拿到coin(5)的情况有一种:
	coin(1) + coin(5);

心得:

dp算法是真的好用!qaq