換零錢:有數量不限的硬幣,幣值為25分、10分、5分和1分,請編寫程式碼計算n分有幾種表示法。
換零錢:
有數量不限的硬幣,幣值為25分、10分、5分和1分,請編寫程式碼計算n分有幾種表示法。
給定一個int n,請返回n分有幾種表示法。保證n小於等於100000,為了防止溢位,請將答案Mod 1000000007。
測試樣例
6
返回:2
動態規劃
dp[i][sum] 使用i 種硬幣組成sum有多少種方式。
設v1,v2,v3,v4 硬幣的面值
sum = v1*x1+ v2*x2 + v3*x3 + v4*k; dp[i][sum]
{x1,x2,x3,k}
{0…x1}
{0…x2}
{0…x3}
{0…k}
k<=sum/v4;
sum_0 = v1*x1+ v2*x2 + v3*x3 + v4*(k); dp[i-1][sum-v4*k]
sum_1 = v1*x1+ v2*x2 + v3*x3 + v4*(k-1); dp[i-1][sum-v4*(k-1)]
sum_2 = v1*x1+ v2*x2 + v3*x3 + v4*(k-2); dp[i-1][sum-v4*(k-2)]
.
.
.
.
.
sum_n = v1*x1+ v2*x2 + v3*x3 + v4*(k-n); dp[i-1][sum-v4*(k-n)]
.
.
.
sum_k = v1*x1+ v2*x2 + v3*x3 +v4*(k-k); dp[i-1][sum]
sum = sum_0+sum_1+sum_2+sum_3+……+sum_n+sum_k;
dp[i][sum]=dp[i-1][sum] + dp[i-1][sum-v4]+….dp[i-1][sum-v4*n] +dp[i-1][sum-v4*k]; k<=sum/v4;
dp[i][sum] 可以由前面的一行得出
程式碼:
二維陣列:
public int countWays(int n) {
int coin[] = new int[]{1,5,10,25};
int dp[][] = new int[5][n+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){
for(int k=0;k<=j/coin[i-1];++k){
dp[i][j]+=dp[i-1][j-k*coin[i-1]];
}
}
}
return dp[4][n];
}
優化為一維陣列:
dp[i][sum]=dp[i-1][sum] + dp[i-1][sum-v4]+….dp[i-1][sum-v4*n] +dp[i-1][sum-v4*k]; k<=sum/v4;
行:我們只需要上一行的資料
列:我們只需要當前sum之前的資料
一次可以使用一維陣列 逐行求解
假設n=20
1 5 10 20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5
3 1 1 1 1 1 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 9
4 1 1 1 1 1 2 2 2 2 2 4 4 4 4 4 4 4 4 4 4 9
public int countWays(int n) {
int[] coin = new int[]{1,5,10,25};
int[] dp = new int[n+1];
dp[0]=1;
for (int i = 0; i < coin.length; i++) {
for (int j = coin[i]; j <= n; j++) {
dp[j] =(dp[j]+dp[j-coin[i]])%1000000007;
}
}
return dp[n];
}
參考:http://www.cnblogs.com/python27/archive/2013/09/05/3303721.html
題目來源:http://www.nowcoder.com/practice/c0503ca0a12d4256af33fce2712d7b24?tpId=8&tqId=11041&rp=3&ru=/ta/cracking-the-coding-interview&qru=/ta/cracking-the-coding-interview/question-ranking