day44 ● 完全背包 ● 518. 零钱兑换 II ● 377. 组合总和 Ⅳ

66 阅读1分钟

本文将使用动态规划解决三道题目:完全背包、零钱兑换 II、组合总和 IV。本篇报告将介绍动态规划的思路以及Java代码实现。

一、完全背包

完全背包问题是指有一个容量为V的背包和n种不同的物品,每种物品有无限个。第i种物品的体积是v[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。

动态规划的思路:

  1. 定义状态:设f[i][v]表示前i种物品恰好放入一个容量为v的背包可以获得的最大价值。

  2. 状态转移方程:f[i][v]=max{f[i-1][v-kv[i]]+kw[i]|0<=k*v[i]<=v}

  3. 边界条件:f[0][j]=0(0<=j<=V),f[i][0]=0(0<=i<=n)

  4. 最终答案:f[n][V]

Java代码实现:

public static int knapsack(int[] v, int[] w, int V) {
    int n = v.length;
    int[][] f = new int[n + 1][V + 1];
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= V; j++) {
            int maxK = j / v[i - 1];
            for (int k = 0; k <= maxK; k++) {
                f[i][j] = Math.max(f[i][j], f[i - 1][j - k * v[i - 1]] + k * w[i - 1]);
            }
        }
    }
    return f[n][V];
}

二、零钱兑换 II

零钱兑换 II 是一道非常经典的动态规划问题,题目描述如下:给定不同面额的硬币和一个总金额,编写一个函数来计算可以凑成总金额的硬币组合数。假设每一种面额的硬币有无限个。

动态规划的思路:

  1. 定义状态:设f[i][j]表示前i种硬币凑成j元的方案数。

  2. 状态转移方程:f[i][j]=f[i-1][j]+f[i][j-coins[i-1]] (j>=coins[i-1])

  3. 边界条件:f[0][j]=0(0<=j<=amount),f[i][0]=1(0<=i<=n)

  4. 最终答案:f[n][amount]

Java代码实现:

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

三、组合总和 IV

组合总和 IV 是一道非常经典的动态规划问题,题目描述如下:给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。

动态规划的思路:

  1. 定义状态:设f[i]表示凑成i元的方案数。

  2. 状态转移方程:f[i]+=f[i-nums[j]] (i>=nums[j])

  3. 边界条件:f[0]=1

  4. 最终答案:f[target]

Java代码实现:

public static int combinationSum4(int[] nums, int target) {
    int[] f = new int[target + 1];
    f[0] = 1;
    for (int i = 1; i <= target; i++) {
        for (int j = 0; j < nums.length; j++) {
            if (i >= nums[j]) {
                f[i] += f[i - nums[j]];
            }
        }
    }
    return f[target];
}

以上就是三道题目的动态规划思路以及Java代码实现。