377. 组合总和 Ⅳ(dp)
给你一个由 不同 整数组成的数组
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
进阶:如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?
class Solution: def combinationSum4(self, nums: List[int], target: int) -> int: n = len(nums) dp = [0] * (target+1) dp[0] = 1 for i in range(target+1): for j in range(len(nums)): if i - nums[j]>=0: dp[i] += dp[i-nums[j]] return dp[target]
超时
class Solution { public: int combinationSum4(vector<int>& nums, int target) { if (target==0) { return 1; } int res = 0; for (auto num : nums) { if (target-num>=0) { res += combinationSum4(nums,target-num); } } return res; } };
备忘录
class Solution { public: int help(vector<int>& nums, int target,vector<int>& memo) { if (memo[target]!=-1) return memo[target]; if (target==0) { return 1; } int res = 0; for (auto num : nums) { if (target-num>=0) { res += help(nums,target-num,memo); } } memo[target] = res; return res; } int combinationSum4(vector<int>& nums, int target) { vector<int> dp = vector<int>(target+1,-1); dp[0] = 1; int res = help(nums,target,dp); return res; } };
dp
int combinationSum4(vector<int>& nums, int target) { vector<unsigned int> dp = vector<unsigned int>(target+1,0); dp[0] = 1; for(int i = 1; i <= target;i++) { for(auto num : nums) { if (i-num>=0) { dp[i] += dp[i-num]; } } } return dp[target]; }
本题与「完全背包求方案数」问题的差别在于:选择方案中的不同的物品顺序代表不同方案。
举个 🌰,在「完全背包」问题中,凑成总价值为 6 的方案 [1,2,3] 算是 11 种方案,但在本题算是 3 * 2 * 1 = 63∗2∗1=6 种方案([1,2,3],[2,1,3],[3,1,2] ... )。
class Solution { public: int combinationSum4(vector<int>& nums, int target) { int len = target; vector<vector<unsigned long long >> dp (len+1,vector<unsigned long long>(target+1,0)); dp[0][0] = 1; for (int i = 1;i <= len;++i) { for(int j =0;j <=target;j++) { for (int x : nums) { if (j-x>=0) { dp[i][j] += dp[i-1][j-x]; } } } } int sum = 0; for (int k =0;k <=target;k++) { sum +=dp[k][target]; } return sum; } };