0-1背包、完全背包算法模板从递归到记忆化搜索到动态规划

0-1背包、完全背包算法模板从递归到记忆化搜索到动态规划

不管是0-1背包还是完全背包,我们都可以将问题转换成为选择或者不选的问题,这个问题在前面的回溯算法模板是一样的。
举个栗子:
假如有1、4、5这三个数,问组成和为12的数需要多少个?
这时候就是遍历这个数组,1需不需要 在原来的基础上 4 需不需要 ,5需不需要,经过多次比较之后能得到最终的结果。
题目:
在这里插入图片描述

# 递归 + 记忆化搜索(缓存)
class Solution {
    private int[] coins;
    private int[][] memo;

    public int coinChange(int[] coins, int amount) {
        this.coins = coins;
        int n = coins.length;
        memo = new int[n][amount + 1];
        for (int[] row : memo) {
            Arrays.fill(row, -1); // -1 表示没有访问过
        }
        int ans = dfs(n - 1, amount);
        return ans < Integer.MAX_VALUE / 2 ? ans : -1;
    }

    private int dfs(int i, int c) {
        if (i < 0) {
            return c == 0 ? 0 : Integer.MAX_VALUE / 2; // 除 2 防止下面 + 1 溢出
        }
        if (memo[i][c] != -1) { // 之前计算过
            return memo[i][c];
        }
        if (c < coins[i]) {
            return memo[i][c] = dfs(i - 1, c);
        }
        return memo[i][c] = Math.min(dfs(i - 1, c), dfs(i, c - coins[i]) + 1);
    }
}

题目基本上还是完全背包,主要看dfs的内容。
i 依次从数组的最后一个依次往前面走,走到当前这个位置有两种情况,分别是选和不选,如果是选当前的这个情况,由于当前这个硬币拿了之后,下一次仍然可能拿,所以我们下一次的起点仍然是i。另外一种情况是当前这种情况不拿,那么直接进入到下一个状态,也就是可以i - 1.
最后比较这两种状态哪一种状态需要的个数少。
注意点:

  1. 由于题目要求的是最少的,所以对于一些越界的情况,不可达的情况我们都设置成为最大值,之后这条路就不会进行选择。
  2. 需要注意第一个判断条件之后返回的情况

下一步:
单纯使用递归进行搜索,肯定会超时,这时候我们会在原来的接触上直接加上一个缓存,用于记录当前这个状态的结果吗,下一次计算这个位置的时候,就不用重新计算,直接进行拿就可以。
如果dfs中用到了几个变量,那么我们设置数组的时候基本上就是几维的。
下一步动态规划:

class Solution {
    public int coinChange(int[] coins, int amount) {
        int n = coins.length;
        int[][] f = new int[n + 1][amount + 1];
        Arrays.fill(f[0], Integer.MAX_VALUE / 2); // 除 2 防止下面 + 1 溢出
        f[0][0] = 0;
        for (int i = 0; i < n; i++) {
            for (int c = 0; c <= amount; c++) {
                if (c < coins[i]) f[i + 1][c] = f[i][c];
                else f[i + 1][c] = Math.min(f[i][c], f[i + 1][c - coins[i]] + 1);
            }
        }
        int ans = f[n][amount];
        return ans < Integer.MAX_VALUE / 2 ? ans : -1;
    }
}

到了这里就能发现是大家之前数值的递归方程,我们都会疑惑这个方程是从哪里来的,其实通过查看这个递归方程是不是和上面dfs上面的状态转移方程有点相似,其实是一样的。将我们原来每一步的操作转换成为填表的一个过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WeChat098

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值