动态规划完全背包

我们之前说过01背包,因为就是一个物品要么放要么不放。

假如一种物品有无限个,那么就是完全背包了

518

给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。

请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。

假设每一种面额的硬币有无限个。 

题目数据保证结果符合 32 位带符号整数。

示例 1:

输入:amount = 5, coins = [1, 2, 5]
输出:4
解释:有四种方式可以凑成总金额:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
示例 2:

输入:amount = 3, coins = [2]
输出:0
解释:只用面额 2 的硬币不能凑成总金额 3 。
示例 3:

输入:amount = 10, coins = [10] 
输出:1

 

01背包那个我是"物够倒包",也就是先物再包,然后倒着来,为什么倒着来?

确定一个物品就放一次。

那么无限次是怎么回事?就是正着来。

 int[] dp = new int[amount+1];
         dp[0] = 1;
          for (int i=0; i<coins.length ; i++) { //物
             for (int j=coins[i]; j<=amount ; j++) { //够正包
                // dp[j] = dp[j] + dp[amount-coins[i]];
                dp[j] = dp[j] + dp[j-coins[i]];
             }
          }
         return dp[amount];
    }

我们想想这两个for都是啥意思啊

外层:遍历物品,比如[1,3]那你第一次就只能拿1去怼了,第二次就只能拿3去了

如果把物和包换过来,那么就可以无视物品顺序了

377. 组合总和 Ⅳ
力扣题目链接(opens new window)

难度:中等

给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。

示例:

nums = [1, 2, 3]
target = 4
所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1)

请注意,顺序不同的序列被视作不同的组合。

因此输出为 7。

解答:物品和包倒过来就可以了

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

所以发现没有,物在里遍历就是组合数!我们可以记成   组合里物   !

来我们回去爬楼梯,组合一下【礼物】

leetcode70

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

 

这题很经典嘛。

我们会发现,比如说现在楼梯是3,[2,1]和[1,2]明显是两种不同的爬法!

不同就是组合数!

上法宝,组合里物,物在里头遍历,那么正着还是倒着?肯定是正着啊,1和2能用无限次。

这是个完全背包。

class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[n+1];
        dp[0] = 1;
        if(n<2)return 1;
        if(n==2)return 2;
        for (int i=1; i<=n ; i++) {  
            for (int j=1; j<=2 ; j++) { //里物,里头遍历物体
                if(i>=j)  //完全背包里头一般都得判断一下
                   dp[i] += dp[i-j];
            }
        }
        return dp[n];
    }
}

 

leetcode 322 零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1
示例 2:

输入:coins = [2], amount = 3
输出:-1
示例 3:

输入:coins = [1], amount = 0
输出:0

提示:

1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104

为啥我这次非要把提示一块粘贴了呢,后面我们就知道。

首先一看这就是个完全背包,没的说,求的是最小值,那我们就没必要求组合数了,组合里物派不上用场,物品外头遍历去。

我们很快能这么写:

87626b554d7c458cad1f9c548c34356e.jpg

 然后发现,我靠,溢出来了!为啥,因为

a447f332d596445896f539a8ca94df2a.jpg

你特码加一了!

那咋办!哎,提示说了,amount不大于10的四次方啊

那我们不要啥MAXvalue了,换成10001不就可以了吗!哎,上面红色的部分换成10001 就可以了。顺便一提,dp[0]记得初始化啊。arrays.fill不是初始化,那就是为了返回个最小值

什么叫初始化?一定是初始化成对的!不对的数那叫临时赋值。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值