QUESTION
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?
THOUGHT I
这道题跟以前的不一样的地方在于只要求给出组合的数目,不要求给出组合,开始的想法是按照以前的做法去做,不过他这里允许出现[1,2,2],[2,1,2],[2,2,1]这样的组合,也就是说可以往回去找数值。
CODE
public class Solution {
public int combinationSum4(int[] nums, int target) {
if(nums == null || nums.length == 0 || target == 0)
return 0;
List<Integer> temp = new ArrayList<>();
Arrays.sort(nums);
return helper(nums,target,temp,0);
}
public int helper(int[] nums,int target,List<Integer> temp,int count){
if(target == 0){
count++;
return count;
}
if(target < 0)
return count;
for(int i = 0;i < nums.length;i++){
if(nums[i] > target)
return count;
target -= nums[i];
temp.add(nums[i]);
helper(nums,target,temp,count);
target += nums[i];
temp.remove(temp.size() - 1);
}
return count;
}
}
RESULT
超时了。
THOUGHT II
count[target] = sum(count[target - nums[i]]), where 0 <= i < nums.length, and target >= nums[i].
target是由哪些比它小的数组合得到的,举例来说,数组nums为{1,2},target为5,那么count[5] = count[5-1]+count[5-2];和换零钱的思路是一样的,钱的总数是5块,零钱有1块和两块的,那么换五块钱的组合数为换4块钱的组合数加上换3块钱的组合数,【这里真是不好理解】而换三块钱的组合数为换一块钱的组合数加上换两块钱的组合数,换一块钱的组合数为1,换两块钱的组合数为2,所以换三块钱的组合数为3.换四块钱的组合数为换三块钱的组合数加上换两块钱的组合数为3+2=5,所以最后结果为8.
CODE
public class Solution {
public int combinationSum4(int[] nums, int target) {
if(target == 0)
return 1;
int res = 0;
for(int i = 0;i < nums.length;i++){
if(target >= nums[i])
res += combinationSum4(nums,target - nums[i]);
}
return res;
}
}
result
超时了,递归的方法做的时间复杂度不会算额。。。
THOUGHT II
上面的思路是好的,但是进行了大量的多余计算,比如我已经算出换四块钱的组合数了,但是没有保存下来,结果导致我下次还得去算一遍,所以效率很低。这次我们用一个数组dp来保存已经算出来的结果。
CODE
public class Solution {
public int combinationSum4(int[] nums, int target) {
int[] DP = new int[target + 1];
DP[0] = 1;
for(int i = 1;i <= target;i++){
for(int num : nums){
if(i >= num)
DP[i] += DP[i - num];
}
}
return DP[target];
}
}
result
time complexity is O(m * n),space complexity is O(m)