代码随想录第四十四天 | 完全背包&&零钱兑换II&&组合总和IV
完全背包理论
有N件物品和一个最多能背重量W的背包。第i件物品的重量是weight[i],得到的价值是value[i]。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。
完全背包和01背包问题唯一不同的地方就是,每件物品都有无限件。
01背包的背包内嵌循环是从大到小的,是为了保证每一件物品仅被添加一次。
而完全背包的物品是可以添加多次的,所以要从小到大去遍历:
1 | // 先遍历物品,再遍历背包 |
1 | / 先遍历背包,再遍历物品 |
纯完全背包 是凑成背包价值最大是多少。
518.零钱兑换II
文章:19. 零钱兑换II
题目:518. 零钱兑换 II
【思路】
钱币不限,完全背包问题。
和纯完全背包的凑成背包最大值是多少不同,本题是要求凑成总金额的物品组合个数
组合数! 而不是排列数。(去重)
组合不强调元素之间的顺序,排列强调元素之间的顺序。
1.确定数组及其下标含义
dp[j]:凑成总金额j的货币组合个数为dp[j](金额是背包,货币是物品)
2.确定递推公式
dp[j] 就是所有dp[j-coins[i]]的相加
所以递推公式是dp[j] += dp[j - coins[i]]
3.dp数组如何初始化
dp[0]一定要是1,是累加递归的基础。
4.确定遍历顺序
本题求的是组合数,对排列的顺序要求是去重,因此需要规定for循环的先后顺序。
物品在外边:物品只遍历一次,不重复遍历(组合数)
背包在外面:物品多次遍历(排列数)
5.举例推导。。
- Java实现
1 | class Solution { |
- Go实现
1 | func change(amount int, coins []int) int { |
377.组合总和IV
文章:21. 组合总和Ⅳ
题目:377. 组合总和 Ⅳ
【思路】
本题提到找出和为给定目标正整数的组合的个数。而给的样例是顺序不同视作不同的组合,其实求的是排列数。
这题就是和上题差不多,求的是排列数,换一下背包和物品的遍历顺序以及改一下变量就好噜。
- Java实现
1 | class Solution { |
- Go实现
1 | func combinationSum4(nums []int, target int) int { |
【算法总结】
- 零钱兑换II:因为零钱的数量是无限的,因此采用完全背包。题目示例提出求的是组合数(去重),因此采用物品在外循环,背包在内循环,这样保证了物品只被循环一次。
- 组合总和IV:因为数字的个数是无限的,因此采用完全背包。题目示例提出求的是排列数(不同的排列均算入答案),因此采用背包在外循环,物品在内循环,这样保证了物品会被多次循环。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 林重笑!