前言
动态规划专题,从简到难通关动态规划。
每日一题
今天的题目是 377. 组合总和 Ⅳ,难度为中等
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
示例 1:
输入: nums = [1,2,3], target = 4 输出: 7 解释: 所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) 请注意,顺序不同的序列被视作不同的组合。
示例 2:
输入: nums = [9], target = 3 输出: 0
提示:
1 <= nums.length <= 2001 <= nums[i] <= 1000nums中的所有元素 互不相同1 <= target <= 1000
进阶: 如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?
题解
由于题目中的元素可以重复使用,那么这么道题就是一道完全背包问题
注意题目中顺序不同的会被视为不同的组合,那么其实就是求排列个数。
- 确定dp数组以及下标的含义
定义一个一维的动态规划数组 dp,其中 dp[i] 表示凑出总和为 i 的排列数。
- 确定递推公式
dp[i] += dp[i - nums[j]]
对于数组中的每个元素 num,遍历 dp 数组。
当 i > num 时,dp[i] += dp[i-num]。 其中,dp[i] 表示凑出总和为 i 的组合数,num 表示数组中的元素值。当选择当前元素 num 时,可能的组合数为 dp[i-num],因为只需要再凑出 i-num 的总和即可。因此,dp[i] 要加上 dp[i-num] 的值。遍历结束后,dp[target] 即为总和为 target 的元素组合个数。
- 初始化ap数组
因为递推公式 dp[i] += dp[i - nums[j]]的 缘故,dp[0] 要初始化为1,这样递归其他 dp[i] 的时候才会有数值基础。
所以讲 dp[0] 初始化为 1,其他位置初始化为 0
- 确定遍历顺序:
遍历 dp 数组时,外层循环按照 nums 中元素的顺序遍历,内层循环按照 dp 数组的范围遍历。
- 举例推导dp数组
| i | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| dp | 1 | 1 | 2 | 4 | 7 |
代码:
function combinationSum4(nums: number[], target: number): number {
const dp = new Array(target + 1).fill(0);
dp[0] = 1;
for (let i = 1; i <= target; i++) {
for (let num of nums) {
if (num <= i) {
dp[i] += dp[i - num];
}
}
}
return dp[target];
};