LeetCode518、交換IIの変更(完全なバックパック問題)

タイトル説明

https://leetcode-cn.com/problems/coin-change-2/
ここに画像の説明を挿入

解決

完全なナップサック問題、フレーム:

  • 状態の決定は、問題の変数です—1。さまざまな種類のコイン; 2。合計金額; 3。使用されたコインの数;次に、問題に応じて、最初の2つの数量を使用して現在の金額を表すだけです。問題、dp配列が2次元であり、2つの次元がそれぞれ変数1と2に対応することを示します。
  • dp配列の定義:dp [i] [j]は、最初のiコインがjの量を構成できる方法の数を表します。この定義を厳密に信じてください。
  • 再発プロセスを決定します。i番目のコインをロードできる場合は、インストールしないことを選択し、次にdp [i] [j] = dp [i-1] [j]、インストールすることを選択し、次にp [i] [j] = dp [i] [j-coins [i-1]]なので、この場合はdp [i] [j] = dp [i-1] [j] + dp [i] [j-conis [ i-1]];収まらない場合は、dp [i] [j] = d [i-1] [j]
  • 再帰が成功しない場合は、2番目のステップに戻り、dp配列の定義が間違っています。dp配列の定義を再考してください。
  • 境界の状況を考えてみましょう。dp[i] [0]は金額を0にする方法であり、収集しない方法は1つだけです。質問の結果は1、dp [0] [j]です。 = 0は、収集する金貨がないことを意味します。

最後に、コードを記述します。

class Solution {
    
    
    public int change(int amount, int[] coins) {
    
    
        if(amount==0) return 1;
        if( coins==null || coins.length==0) return 0;
        int [][]dp = new int[coins.length+1][amount+1];//表示前i种硬币组合为j元的可能方法数
        //边界 dp[0][j]=0 dp[i][0]=1 
        for(int i=0;i<=coins.length;i++){
    
    
            dp[i][0] = 1;
        }
        //递推方程
        for(int i=1;i<=coins.length;i++){
    
    
            for(int j=1;j<=amount;j++){
    
    
                if(j-coins[i-1]>=0){
    
    //当前硬币装得下
                    dp[i][j] = dp[i-1][j] //不装
                                + dp[i][j-coins[i-1]];//装下该硬币,但是因为数量无限个,可以继续装
                }else//装不下
                    dp[i][j] = dp[i-1][j];
            }
        }
        return dp[coins.length][amount];


    }
}

ここに画像の説明を挿入

次に、ソリューションから、dp [i] [j]が前の2つの状態に関連しており、状態の圧縮を使用してスペースの複雑さを軽減できることがわかります。

  • 1次元配列dp [j]
class Solution {
    
    
    public int change(int amount, int[] coins) {
    
    
        if(amount==0) return 1;
        if( coins==null || coins.length==0) return 0;
        int []dp = new int[amount+1];//表示前i种硬币组合为j元的可能方法数
        //边界 dp[0][j]=0 dp[i][0]=1 
        dp[0] = 1;
        //递推方程
        for(int i=1;i<=coins.length;i++){
    
    
            for(int j=1;j<=amount;j++){
    
    
                if(j-coins[i-1]>=0){
    
    //当前硬币装得下
                    dp[j] = dp[j] //不装
                                + dp[j-coins[i-1]];//装下该硬币,但是因为数量无限个,可以继续装
                }
                // }else//装不下
                //     dp[j] = dp[j];
            }
        }
        return dp[amount];


    }
}

ここに画像の説明を挿入

おすすめ

転載: blog.csdn.net/qq_44861675/article/details/114577408