【完全背包】B001_LC_零钱对换(暴搜 / 记忆化搜索 / dp)

一、题目描述

You are given coins of different denominations and a total amount of money amount.

Write a function to compute the fewest number of coins that you need to make up that amount.

If that amount of money cannot be made up by any combination of the coins, return -1.

Input: coins = [1, 2, 5], amount = 11
Output: 3 
Explanation: 11 = 5 + 5 + 1

Input: coins = [2], amount = 3
Output: -1
Note:
You may assume that you have an infinite number of each kind of coin.

二、题解

方法一:递归

int min;
public int coinChange(int[] coins, int amount) {
    COINS = coins;
    return dfs(amount);
}
private int dfs(int amount) {
    if(amount < 0) return -1;
    if(amount == 0) return 0;
    //因为对每一个硬币都穷举一遍,得出最小的兑换数,所以
    min = Integer.MAX_VALUE;
    for(int coin: COINS) {
        int n = dfs(amount - coin);
        if(n >= 0) min = Math.min(min, n + 1);
    }
    return min == Integer.MAX_VALUE ? -1 : min;
}

复杂度分析

  • 时间复杂度: O ( . . . ) O(...) O(...)
  • 空间复杂度: O ( . . . ) O(...) O(...)

方法二:记忆化搜索

int[] memo = null;
public int coinChange(int[] coins, int amount) {
    COINS = coins;
    return dfsWithMempfs(amount);
}
private int dfsWithMemp(int amount) {
    if(amount < 0) return -1;
    if(amount == 0) return 0;
    if(memo[amount - 1] != 0) return memo[amount - 1];
    int min = Integer.MAX_VALUE;
    for(int coin: COINS) {
        int n = dfsWithMemp(amount - coin);
        if(n >= 0 && n < min) min = n + 1;
    }
    memo[amount - 1] = min == Integer.MAX_VALUE ? -1 : min;
    return memo[amount - 1];
}

复杂度分析

  • 时间复杂度: O ( ) O() O()
  • 空间复杂度: O ( ) O() O()

方法三:dp

  • 状态表示:
    • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示考虑当前 i 号硬币,凑出金额为 j 的最小硬币数。
    • d p [ i ] [ j − c o i n ] dp[i][j-coin] dp[i][jcoin]:表示在硬币面值状态为 j-coin 时的最小硬币数
  • 状态转移:
    • 对于每一个硬币 i 我们都可以从容量为 c o i n s [ i ] coins[i] coins[i] 时开始枚举,若 d p [ i − 1 ] [ j − c o i n s [ j ] ] dp[i-1][j-coins[j]] dp[i1][jcoins[j]] 是无穷大,说明再无法和面值 j-coins[i] 组合出价值为 j 的钱包。
      • 比如 j = 3,coin = 2 时,dp[3-2] = 1,此时 dp[3] = dp[3-2] + 1,表示可以和面值为 3-2=1 时的硬币凑出一种让钱包价值为 3 的组合。
    • d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] ,   d p [ i − 1 ] [ j − c o i n s [ i ] ] ) + 1 dp[i][j] = min(dp[i][j],\ dp[i-1][j-coins[i]]) + 1 dp[i][j]=min(dp[i][j], dp[i1][jcoins[i]])+1
  • 边界情况
    • d p [ 0 ] [ 0 ] dp[0][0] dp[0][0] 表示没有取任何硬币下的最小取法。
    • dp 其余元素可初始化为正无穷,表示有些状态不可达。
public int coinChange1(int[] coins, int amount) {
    final int MAX = Integer.MAX_VALUE;
    int N = coins.length;
    int[] dp = new int[amount + 1];
    Arrays.fill(dp, 1, dp.length, MAX);
    
    for(int coin: coins) 
    for(int j = coin; j <= amount; j++) {
        if(dp[j - coin] != MAX) 
        	dp[j] = Math.min(dp[j], dp[j - coin] + 1);
   	}
    return dp[amount] == MAX ? -1 : dp[amount];
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

你可能感兴趣的:(●,动态规划)