解题思路
常见的背包问题有
1、组合问题。
2、True、False问题。
3、最大最小问题。
1、组合问题:
377. 组合总和 Ⅳ
494. 目标和
518. 零钱兑换 II
2、True、False问题:
139. 单词拆分
416. 分割等和子集
3、最大最小问题:
474. 一和零
322. 零钱兑换
组合问题公式
dp[i] += dp[i-num]
True、False问题公式
dp[i] = dp[i] or dp[i-num]
最大最小问题公式
dp[i] = min(dp[i], dp[i-num]+1)或者dp[i] = max(dp[i], dp[i-num]+1)
以上三组公式是解决对应问题的核心公式。
当然拿到问题后,需要做到以下几个步骤:
1.分析是否为背包问题。
2.是以上三种背包问题中的哪一种。
3.是0-1背包问题还是完全背包问题。也就是题目给的nums数组中的元素是否可以重复使用。
4.如果是组合问题,是否需要考虑元素之间的顺序。需要考虑顺序有顺序的解法,不需要考虑顺序又有对应的解法。
接下来讲一下背包问题的判定
背包问题具备的特征:给定一个target,target可以是数字也可以是字符串,再给定一个数组nums,nums中装的可能是数字,也可能是字符串,问:能否使用nums中的元素做各种排列组合得到target。
背包问题技巧:
1.如果是0-1背包,即数组中的元素不可重复使用,nums放在外循环,target在内循环,且内循环倒序;
for num in nums:
for i in range(target, nums-1, -1):
2.如果是完全背包,即数组中的元素可重复使用,nums放在外循环,target在内循环。且内循环正序。
for num in nums:
for i in range(nums, target+1):
3.如果组合问题需考虑元素之间的顺序,需将target放在外循环,将nums放在内循环。
for i in range(1, target+1):
for num in nums:
代码
class Solution:
def combinationSum4(self, nums: List[int], target: int) -> int:
if not nums:
return 0
dp = [0] * (target+1)
dp[0] = 1
for i in range(1,target+1):
for num in nums:
if i >= num:
dp[i] += dp[i-num]
return dp[target]
作者:Jackie1995
链接:https://leetcode-cn.com/problems/combination-sum-iv/solution/xi-wang-yong-yi-chong-gui-lu-gao-ding-bei-bao-wen-/
来源:力扣(LeetCode)
官方关于状态转移方程的解释不够清楚。我来解释一下.。
先举个例子,nums = [1, 2, 3],target = 35.
假设用1,2,3拼凑出35的总组合个数为y。我们可以考虑三种情况:
(1)有效组合的末尾数字为1,这类组合的个数为
x1。我们把所有该类组合的末尾1去掉,那么不难发现,我们找到了一个子问题,x1即为在[1,2,3]中凑出35 - 1 =
34的总组合个数。因为我如果得到了和为34的所有组合,我只要在所有组合的最后面,拼接一个1,就得到了和为35且最后一个数字为1的组合个数了。(2)有效组合的末尾数字为2,这类组合的个数为
x2。我们把所有该类组合的末尾2去掉,那么不难发现,我们找到了一个子问题,x2即为在[1,2,3]中凑出35 - 2 =
33的总组合个数。因为我如果得到了和为33的所有组合,我只要在所有组合的最后面,拼接一个2,就得到了和为35且最后一个数字为2的组合个数了。(3)有效组合的末尾数字为3,这类组合的个数为
x3。我们把所有该类组合的末尾3去掉,那么不难发现,我们找到了一个子问题,x3即为在[1,2,3]中凑出35 - 3 =
32的总组合个数。因为我如果得到了和为32的所有组合,我只要在所有组合的最后面,拼接一个3,就得到了和为35且最后一个数字为3的组合个数了。这样就简单了,y = x1 + x2 + x3。而x1,x2,x3又可以用同样的办法从子问题得到。状态转移方程get!