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 <= 200
1 <= nums[i] <= 1000
nums
中的所有元素 互不相同1 <= target <= 1000
进阶: 如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?
题解¶
本题的思路与70. 爬楼梯相同。此处使用记忆化递归解决。
设\(f(x; S)\)为给定整数集合\(S\),组成目标值\(x\)的组合数量,我们默认\(0\in S\)。
- 当\(x < 0\),由于\(\forall y\in S, y\geq 0\),不可能得到小于\(0\)的数值,有\(f(x; S) = 0\)
- \(x = 0\),由于默认\(0\in S\),有\(f(x; S) = 1\)。
- 当\(x < 0\),\(S\)中的任意元素\(y\)都可以选择,选择\(y\)得到的组合个数为\(f(x - y; S)\)
因此,得到\(f(x; S)\)的表达式:
\[
f(x; S)=\left\{
\begin{aligned}
& 0 & x < 0 \\
& 1 & x = 0 \\
& \sum_{y\in S} f(x - y; S) & x > 0
\end{aligned}
\right .
\]
由于计算过程中会重复计算某些\(f(x; S)\),可以使用一个数组记录所有已经计算过的\(f(x; S)\)。
int helper(int *dp, int *nums, int numsSize, int target)
{
if (target == 0)
return 1;
if (target < 0)
return 0;
if (dp[target - 1] < 0)
{
int ret = 0, i = 0;
for (i = 0; i < numsSize; i++)
ret += helper(dp, nums, numsSize, target - nums[i]);
dp[target - 1] = ret;
}
return dp[target - 1];
}
int combinationSum4(int* nums, int numsSize, int target) {
int *dp = (int *)malloc(sizeof(int) * target);
memset(dp, 0xff, sizeof(int) * target);
return helper(dp, nums, numsSize, target);
}