1 组合总和 Ⅳ
1.1 题目链接
1.2 题目描述
给你一个由 不同 整数组成的数组 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
1.3 解法(动态规划)
算法思路:
⼀定要注意,我们的背包问题本质上求的是「组合」数问题,⽽这⼀道题求的是「排列数」问题。
因此我们不能被这道题给迷惑,还是⽤常规的 dp 思想来解决这道题。
-
状态表⽰:
- 这道题的状态表⽰就是根据「拆分出相同⼦问题」的⽅式,抽象出来⼀个状态表⽰:
- 当我们在求 target 这个数⼀共有⼏种排列⽅式的时候,对于最后⼀个位置,如果我们拿出数组中的⼀个数 x ,接下来就是去找 target - x ⼀共有多少种排列⽅式。
- 因此我们可以抽象出来⼀个状态表⽰:
- dp[i] 表⽰:总和为 i 的时候,⼀共有多少种排列⽅案。
-
状态转移⽅程:
- 对于 dp[i] ,我们根据「最后⼀个位置」划分,我们可以选择数组中的任意⼀个数nums[j] ,其中 0 <= j <= n - 1 。
- 当 nums[j] <= target 的时候,此时的排列数等于我们先找到 target - nums[j] 的⽅案数,然后在每⼀个⽅案后⾯加上⼀个数字 nums[j] 即可。
- 因为有很多个 j 符合情况,因此我们的状态转移⽅程为:
- dp[i] += dp[target - nums[j] ,其中 0 <= j <= n - 1 。
-
初始化:
当和为 0 的时候,我们可以什么都不选,「空集」⼀种⽅案,因此 dp[0] = 1 。
-
填表顺序:
根据「状态转移⽅程」易得「从左往右」。
-
返回值:
根据「状态表⽰」,我们要返回的是 dp[target] 的值。
1.4 C++算法代码:
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<double> dp(target + 1);
dp[0] = 1;
for(int i = 1; i <= target; i++)
for(int e : nums)
if(i >= e)
dp[i] += dp[i - e];
return dp[target];
}
};