我们之前说过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
为啥我这次非要把提示一块粘贴了呢,后面我们就知道。
首先一看这就是个完全背包,没的说,求的是最小值,那我们就没必要求组合数了,组合里物派不上用场,物品外头遍历去。
我们很快能这么写:
然后发现,我靠,溢出来了!为啥,因为
你特码加一了!
那咋办!哎,提示说了,amount不大于10的四次方啊
那我们不要啥MAXvalue了,换成10001不就可以了吗!哎,上面红色的部分换成10001 就可以了。顺便一提,dp[0]记得初始化啊。arrays.fill不是初始化,那就是为了返回个最小值
什么叫初始化?一定是初始化成对的!不对的数那叫临时赋值。