跳转至

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

进阶: 如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?

Reference

题解

本题的思路与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);
}

评论