- Total Accepted: 33521
- Total Submissions: 80346
- Difficulty: Medium
- Contributor: LeetCode
Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.
Example:
nums = [1, 2, 3] target = 4 The possible combination ways are: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) Note that different sequences are counted as different combinations. Therefore the output is 7.
Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?
解题思路:
要使得某一组合的和为target,我们可以把这个问题分解,假设最后加的一个数为k,那么上一步所得到的和值为target-k,i可以是数组中的任意一个数。
记f(k)为和值为k的组合数,那么f(k) = sum{f(k - nums[i])},当0 < i < nums.size且k ≥ nums[i]。当k=0时,只有一种组合数,就是什么都不选取。
因此,很容易得到这个问题的一个递归解法,代码如下:
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int res = 0;
if(target == 0)
return 1;
for(int i = 0; i < nums.size(); i++){
if(nums[i] <= target)
res += combinationSum4(nums, target - nums[i]);
}
return res;
}
};
但是使用递归会进行许多不必要的重复计算,十分费时。使用动态规划效率会更高。考虑到所计算的f(k)中k的最大值不会超过target,因此可以用一个大小为target的数组来储存所有的f(k)值,以避免重复计算。先给数组所有位置赋值-1,在每次需要计算f(k)之前先查看数组a[k]是否为-1,若不是,则说明f(k)已经在之前计算过,只需要使用数组里储存的值。若之前没有计算过,则计算一次,并把结果写入数组。代码如下:
class Solution {
public:
vector<int> res;
int comb(vector<int>& nums, int target){
if(res[target] != -1)
return res[target];
int temp = 0;
for(int i = 0; i < nums.size(); i++){
if(nums[i] <= target)
temp += comb(nums, target - nums[i]);
}
res[target] = temp;
return temp;
}
int combinationSum4(vector<int>& nums, int target) {
int size = target + 1;
while(size --)
res.push_back(-1);
res[0] = 1;
return comb(nums, target);
}
};
然而这种方法是target不断减小的方法,我们还可以采用不断增大target的方法。这样每次需要计算的f(k - nums[i])都一定是在之前已经计算过的,就不需要再考虑判断是否计算过。代码如下:
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<int> res(target + 1, 0);
res[0] = 1;
for(int i = 1; i < res.size(); i++){
for(int j = 0; j < nums.size(); j++){
if(i >= nums[j])
res[i] += res[i - nums[j]];
}
}
return res[target];
}
};