【程式設計師面試金典】有數量不限的硬幣,幣值為25分、10分、5分和1分,請編寫程式碼計算n分有幾種表示法。

HelloZEX發表於2018-07-26

題目描述

有數量不限的硬幣,幣值為25分、10分、5分和1分,請編寫程式碼計算n分有幾種表示法。

給定一個int n,請返回n分有幾種表示法。保證n小於等於100000,為了防止溢位,請將答案Mod 1000000007。

測試樣例:

6
返回:2

參考騎著炮彈進城提到的dp方法

這裡補充一些解釋,如有錯漏,還請指正。

我們用dp[i](i屬於1~n ) 表示組合成i元一共有幾種方法。

 

首先所有的硬幣組合問題都要有基礎面值:1元。i的總組合方法一定等於i中最後coin元不用新面值的方法+最後coin元使用新面值的方法。

 

而最後coin元 使用新面值的方法必然等於i-coin的總組合方法。

不用新面值的方法就是舊值

 

假如只有1元,那對於任給的1~n,必然只有1中組合方法。

假設增加一種新面值:coin元。對於任意i(i屬於1~n),

當i<coin的時候,新面值組合方法為0,dp[i]不變。

當i=coin,新組合方法為1,總dp[i]=舊dp[i]+1

當coin<i<2coin,新組合方法仍然為1,總dp[i]=舊dp[i] + 新dp[i-coin]

當i=2coin,仍然有總 dp[i]=舊dp[i] + 新dp[i- coin]

以coin=2為例

 

同樣的道理,題目coin值取值為:[1 5 10 25],迭代處理即可

程式碼如下:

class Coins {
public:
    int countWays(int n) {
        // write code here
        int coins[4]={1,5,10,25};
        int dp[100001]={0};       
        dp[0]=1;
        for(int i=0;i<4;i++)
            for(int j=coins[i];j<=n;j++)
                dp[j] =(dp[j]+dp[j-coins[i]])%1000000007;     
        return dp[n];
    }
};

https://blog.csdn.net/cy13299138237/article/details/50474271

問題描述:

  有數量不限的硬幣,幣值為25分、10分、5分和1分,請編寫程式碼計算n分有幾種表示法。

求解思路:

  這也是典型的動態規劃問題,我們可以這樣考慮:當只有1分的硬幣時,n從1到n分別有多少種表示方法;當有1分和5分的硬幣時,n從1到n分別有多少種表示方法,因此類推,直到我們將1分、5分、10分和25分的硬幣全部使用完。思想類似於0-1揹包問題,0-1揹包問題的具體求解方法可以參考我的上一篇部落格動態規劃之0-1揹包問題。我們用陣列coins[i]={1,5,10,25}表示各種幣值,此時可以維護一張二維表ways[i][j],其中橫座標表示前i種表示幣值,j表示硬幣的總值,則ways[i][j]表示能用前i種硬幣來表示j分的方法數。

 當增加一種新的硬幣幣值時,有兩種情況:

(1)不加入此種幣值:ways[i][j]=ways[i-1][j];

(2)加入此種幣值:加入該枚硬幣之前的方法數為ways[i][j-coins[i]],那麼加入該枚硬幣之後構成j分的方法數也為ways[i][j-coins[i]]。

 因此當增加一種新的幣值時,j分的表示方法數為ways[i][j]=ways[i-1][j]+ways[i][j-coins[i]]。

程式碼實現

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] coins = {1, 5, 10, 25};
        int[][] ways = new int[4][n + 1];
        for (int i = 0; i < 4; i++)
            ways[i][0] = 1; //第0行初始化為1
        for (int j = 1; j <= n; j++)
            ways[0][j] = 1; //第0列初始化為1
        for (int i = 1; i < 4; i++) {
            for (int j = 1; j <= n; j++) {
                if (j >= coins[i])
                    ways[i][j] = ways[i - 1][j] + ways[i][j - coins[i]];
                else
                    ways[i][j] = ways[i - 1][j];
            }
        }
        System.out.println(ways[3][n]);
    }
}

當然,維護二維表未免過於複雜,我們可以維護一張一維表,即用一維陣列ways[j]來記錄j分的表示方法數。改進的程式碼實現如下:

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int []coins={1,5,10,25};
        int []ways=new int[n+1];
        ways[0]=1;
        for(int i=0;i<4;i++){
            for(int j=coins[i];j<=n;j++){
                ways[j]=ways[j]+ways[j-coins[i]];
            }
        }
        System.out.println(ways[n]);
    }
}

 

相關文章