1. 程式人生 > >硬幣找零,即數字和為sum的幾種問題

硬幣找零,即數字和為sum的幾種問題

問題一

1.問題描述
假設有幾種硬幣,如1、3、5,並且數量無限。請找出能夠組成某個數目的找零所使用最少的硬幣數。

2.問題分析
動態規劃的思想,用 dp[] 存放自底向上問題的解。dp[] 大小為 amount,dp[k] = min(dp[k - coin[i]) + 1

3.Java實現

public int coinChange(int[] coins, int amount) {
    int max = amount + 1;             
    int[] dp = new int[amount + 1];  
    //先令 dp[] 初始化為 amount + 1
Arrays.fill(dp, max); //當 amount = 0 時,解也是 0 dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int j = 0; j < coins.length; j++) { if (coins[j] <= i) { dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); } } } //如果 dp[amount] > amount,即還是初始化的值,說明無解
return dp[amount] > amount ? -1 : dp[amount]; }

問題二

1.問題描述
將上題中的求最小的硬幣數,改成所有的方案。即,假設有幾種硬幣,並且數量無限。請找出能夠組成某個數目的找零所有的方案數。

2.問題分析
用 dp[i, j] 表示:使用 第 1,2,…i 種面值的硬幣時,需要找金額為 j 的錢,最多可採用多少種不同的方式。
i 表示可用的硬幣種類數, j 表示 需要找回的零錢
有兩種情況:對於某種面值的硬幣,要麼使用了它,dp[i, j - coins[i]]
要麼不使用它,dp[i - 1, j]
所以,dp[i, j] = dp[i, j - coins[i]] + dp[i - 1, j]

3.Java實現

public int coinChangeWays(int[] coins, int n){
    int m = coins.length;
    int[][] dp = new int[m+1][n+1];

    //第一列 dp[i][0] 表示用coins[i]組成面額為0的錢的方案,即不需要任何貨幣,初始化為1
    for(int i = 0; i <= m; i++)
        dp[i][0] = 1;
    //第一行 dp[0][j] 沒有貨幣,初始化為0
    for(int i = 1; i <= n; i++)
        dp[0][i] = 0;

    for(int i = 1; i <= m; 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]];
            else 
                dp[i][j] = dp[i - 1][j];
        }
    }
    return dp[m][n];
}

問題三

1.問題描述
將上題中硬幣無限量使用,改為每個面值只有一個硬幣。即,假設有幾種硬幣,每種硬幣只有一個。請找出能夠組成某個數目的找零所有的方案數。

題目還可以這樣,同一個意思:
給定一個有n個正整數的陣列A和一個整數sum,求選擇陣列A中部分數字和為sum的方案數。
當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。

2.問題分析
也是兩種方法:要麼加這個數,dp[i - 1, j - weight[i]]。和上題不同的只是,加上這個數,i 也要減一。
要不不加這個數,dp[i - 1, j]
所以,dp[i, j] = dp[i-1, j] + dp[i-1, j-weight[i]]

3.Java實現

public int sunWays(int[] weight, int sum) {
    int n = weight.length;
    int[][] dp = new int[n+1][sum+1];

    for (int i = 0 ; i < n ;i++) {
        dp[i][0] = 1;
    }
    for (int j = 1 ; j < sum ;j++) {
        dp[0][j] = 0;
    }

    for (int i = 1 ; i <= n ;i++) {
        for (int j = 0 ; j <= sum ;j++) {
            if(weight[i] <= j) 
                dp[i][j] = dp[i-1][j] + dp[i-1][j-weight[i]];
            else 
                dp[i][j] = dp[i-1][j];
        }
    }
    return dp[n][sum];
}

上面的方法,dp[][]用了二維陣列, 也可以用一維陣列來節省空間。

public int sumWays(int[] weight, int sum){
    int dp[]=new int[sum+1];
    dp[0]=1;

    for(int i = 0; i < weight.length; i++){
        for(int j = sum; j >= weight[i]; j--){
           dp[j] = dp[j - weight[i]] + dp[j];
        }
    }
    return dp[sum];
}

相關推薦

硬幣數字sum問題

問題一 1.問題描述 假設有幾種硬幣,如1、3、5,並且數量無限。請找出能夠組成某個數目的找零所使用最少的硬幣數。 2.問題分析 動態規劃的思想,用 dp[] 存放自底向上問題的解。dp[] 大小為 amount,dp[k] = min

硬幣最長上升子序列揹包問題等動態規劃問題詳解

1.硬幣找零 如果我們有面值為 1 元、3 元和 5 元的硬幣若干枚,如何用最少的硬幣湊夠 11 元? 首先我們思考一個問題,如何用最少的硬幣湊夠 i 元(i<11)?為什麼要這麼問呢? 兩個原因:1.當我們遇到一個大問題時,總是習慣把問題的規模變小,這樣便於分析討論。 2.這

滴滴出行 數字sum的方法數(dp)

給定一個有n個正整數的陣列A和一個整數sum,求選擇陣列A中部分數字和為sum的方案數。 當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。 輸入描述: 輸入為兩行: 第一行為兩個正整數n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000

滴滴出行 數字sum的方法數(dp)

給定一個有n個正整數的陣列A和一個整數sum,求選擇陣列A中部分數字和為sum的方案數。 當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。 輸入描述: 輸入為兩行: 第一行為兩個正整數n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000) 第二行為n個正

sincerit 數字sum的方法數(01揹包問題)

題目描述 給定一個有n個正整數的陣列A和一個整數sum,求選擇陣列A中部分數字和為sum的方案數。 當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。 輸入描述: 輸入為兩行: 第一行為兩個正整數n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000) 第二行為

iOS判斷字串中包含數字字母的情況

//直接呼叫這個方法就行 -(int)checkIsHaveNumAndLetter:(NSString*)password{ //數字條件 NSRegularExpression *tNum

斐波那契數列階乘的尾函式優化動態規劃解決最小硬幣揹包問題

// 遞迴是一種解決問題的方法,它解決問題的各個小部分,直到解決最初的大問題。遞迴通常涉及函式呼叫自身 // 斐波那契數列尾呼叫優化 function fibonacci(n, acc1 = 1, acc2 = 1) { if (n === 1 || n === 2) { ret

C#練習 人民幣有100元、50元、10元、5元、2元1元六最少需要準備多少張人民幣

Console.WriteLine("輸入工資"); int money = Convert.ToInt32(Console.ReadLine()); i

[LeetCode] Coin Change 2 硬幣之二

lee diff bit inf may tco nom not leet You are given coins of different denominations and a total amount of money. Write a function t

codevs 3961 硬幣【完全背包DP/記憶化搜索】

得到 可能 代碼 好的 default ++ -h 數值 rip 題目描述 Description 在現實生活中,我們經常遇到硬幣找零的問題,例如,在發工資時,財務人員就需要計算最少的找零硬幣數,以便他們能從銀行拿回最少的硬幣數,並保證能用這些硬幣發工資。

動態規劃——硬幣

max 關系 i++ 是否 coin fine 個數 names std   動態規劃問題,主要在於需要想清楚遞推關系,num[i][j]表示能使用 i 種硬幣時,得到 j 零錢的最優解。   想來就是首先假設只能使用第一種硬幣 1 ,那麽會得到num[ 1 : n] =

leetcode 518. Coin Change 2/硬幣 2

sign script 我們 have fun 數量 -c pub NPU 歸納於http://www.cnblogs.com/grandyang/p/7669088.html 原題https://leetcode.com/problems/coin-change-2/de

動態規劃-硬幣問題四情況

題目1:給定陣列arr,arr中所有的值都是正數且不重複。每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,再給定一個整數aim代表要找的錢數,求組成aim的最少貨幣數。 舉例:  arr[5,2,3],aim=20。  4張5元可以組成20元,其他的找錢方案都要使

劍指offer——出二叉樹n的路徑

連結串列和二叉樹比較難做,主要因其均以鏈相連線,.next and .left 來輸出結構中的資料,無法精確定位,所以通常用遞迴方法實現。 通過遞迴方法,本人感覺最重要的是確定.next的這部中具體實現的操作,然後逐漸實現遞迴。找出二叉樹和為n的路徑,就針對每一步做加和操作以及記錄路徑,並判

輸入一個正整數n輸出所有n的連續正整數序列

1 public static void main(String[] args) { 2 Scanner sc = new Scanner(System.in); 3 while (true) { 4 System.out.prin

sincerit 硬幣之種類數

現存在一堆面值為 1,2,5,10,20,50 面值的硬幣,問給你一個紙幣是m,求出把m紙幣換成硬幣的種類數 思路是動態規劃 假設有n種硬幣,紙幣是m dp[i][j] 表示前i種硬幣能把紙幣換成硬幣的種類數 轉移方程 對於第i種硬幣 dp[i][j] = dp[i-1][j] + dp[i

sincerit 硬幣之最小數量

現存在一堆面值為 1,2,5,10,20,50 面值的硬幣,問找出總值為 N個單位的零錢的所使用的硬幣的數量最少,輸出最小值 #include <iostream> using namespace std; int values[100]; //硬幣面值的陣列 int mai

S的兩個數字/S的連續正數序列

1.和為S的兩個數字,牛客網ac 其實同leetcode第一題兩數之和一樣, 雙指標,從兩邊逼近。 class Solution { public: vector<int> FindNumbersWithSum(vector<int>

牛客國慶集訓派對Day4——G 區間權值(規律雙重字首

題目大意:       小 Bo 有 n 個正整數 a1..an,以及一個權值序列 w1…wn,現在他定義       現在他想知道 的值,需要你來幫幫他。你只需要輸出答案對 109+7 取模

leetcode-322 硬幣問題

我的版本: int coinChange(vector<int>& coins, int amount) { if(coins.size()==0){return -1;} int *dp=new int[amount+1]; for(