Dynamic Planning Series "Change Exchange II"

Given coins of different denominations coinsand a total amount amount. Write a function to calculate the coins that can make up the total amount 组合数. Suppose there are infinite coins of each denomination.

This question is 0-1a variant of the knapsack problem, which is a complete knapsack problem, so what is a complete knapsack problem?

Let's review the problem of 0-1 backpack again : give you a Wbackpack and Nitems (each item is different) that can be loaded with a weight of 1 , and each item has two attributes: weight and value. iThe weight of the first item is wt[i]and the value is val[i]. Now let you use this backpack to pack the item, what is the maximum value that can be loaded?

0-1The number of items in the backpack problem is limited. To be precise, each item is unique, and there are infinite coins of each denomination here. That is 完全背包问题, the idea is the same as the idea of ​​a 0-1 backpack, but The state transition equation is slightly changed.

We can 0-1solve this problem according to the idea of ​​backpack :

We compare coins of different denominations to 0-1items in the knapsack problem, and compare the total amount to the capacity of the knapsack, so that it can be transformed into a knapsack problem model for solution.

  1. The first step: clarify "status" and "choice"

There are two states, namely "the capacity of the backpack" and "optional items", the choice is "pack in the backpack" or "not in the backpack".

for 状态1 in 状态1的所有取值:
    for 状态2 in 状态2的所有取值:
        for ...
            dp[状态1][状态2][...] = 计算(选择1,选择2...)
  1. Clear definition of arraydp

dp[i][j]Is defined as follows: only the first itwo items, when the capacity of the backpack jwhen there are dp[i][j]ways to fill the backpack.

Converted to a coin changer model is to: use only coinsthe front icoins face value, if you want Couchu amount j, there are dp[i][j]kinds of error method.

The base case is dp[0][..] = 0, dp[..][0] = 1. Because if you don't use any coin face value, you can't make up any amount; if the target amount is 0, then "rule by doing nothing" is the only way to make up.

Our ultimate goal is to find dp[N][amount], which Nis the coinssize of the array.

  1. According to "choice", think about the logic of state transition

If you do not use coins[i]the face value of the coin, so Couchu denomination jseveral methods dp[i][j]should be equal dp[i-1][j], inherited the previous results.

If you use coins[i]the face value of the coin, it dp[i][j]should be equal dp[i][j-coins[i-1]].

First, as iit is from the beginning, so coinsthe index is i-1time represents the iface value of the coins.

dp[i][j-coins[i-1]]It is not difficult to understand that if you decide to use this coin, then you should pay attention to how to collect the amount j - coins[i-1].

In sum it is two options, and we want to ask of dp[i][j]a "total number of species and error", so dp[i][j]the value should be more than the sum of the results of the two options:

class Solution {
    
    
    int change(int amount, int[] coins) {
    
    
        int n = coins.length;
        int[][] dp = amount int[n + 1][amount + 1];
        for (int i = 0; i <= n; i++) {
    
    
            dp[i][0] = 1;
        }
        for (int i = 1; i <= n; 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[n][amount];
    }
}

Moreover, we can discover through observation, dptransfer the array and only dp[i][..]and dp[i-1][..]relevant:

Insert picture description here
Therefore, the state can be compressed to further reduce the space complexity of the algorithm:

class Solution {
    
    
    public int change(int amount, int[] coins) {
    
    
        int n = coins.length;
        int[] dp = new int[amount + 1];
        dp[0] = 1; 
      
        for (int i = 0; i < n; i++){
    
    
            for (int j = 1; j <= amount; j++){
    
    
                if (j - coins[i] >= 0){
    
    
                    dp[j] += dp[j-coins[i]];
                }
            }
        }
        return dp[amount];
    }
}

It can even do this:

class Solution {
    
    
    public int change(int amount, int[] coins) {
    
    
        int[] dp = new int[amount + 1];
        dp[0] = 1;

        for (int coin : coins) {
    
    
            // j直接从coin开始,避免了j - coins[i] >= 0的判断
            for (int j = coin; j <= amount; j++) {
    
       
              	dp[j] += dp[j - coin];
            }
        }
        return dp[amount];
    }
}

Time complexity O(N*amount)

Space complexity O(amount)

Guess you like

Origin blog.csdn.net/weixin_44471490/article/details/109132075