Combination Sum
Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
The same repeated number may be chosen from C unlimited number of times.
Note:
- All numbers (including target) will be positive integers.
- Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
- The solution set must not contain duplicate combinations.
For example, given candidate set 2,3,6,7 and target 7,
A solution set is:
[7]
[2, 2, 3]
Solution1
- 这是一道典型的回溯题。每次都尝试加入一个数,若当前得到的和还不够,则继续加入该数,直到和大于target,如果和等于target则得到一个解,若大于则回溯一个数,然后尝试数组中的下一个数。
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
List<List<Integer>> result = new ArrayList<List<Integer>>();
help(candidates,0,target,result,new ArrayList<Integer>());
return result;
}
public void help(int[] candidates,int index,int target,List<List<Integer>> result,List<Integer> item){
if(target==0){
result.add(item);
return;
}
if(target<0||index>=candidates.length) return;
for(int i=index;i<candidates.length;i++){
if(target<candidates[i]) return;//因为数组已经排过序,所以后面的数都没必要再去遍历
List<Integer> temp = new ArrayList<Integer>(item);
temp.add(candidates[i]);
help(candidates,i,target-candidates[i],result,temp);
}
}
}
Solution2
- 理论上,任何递归解法都可以用迭代解法来实现,而迭代一般要借用栈的实现,这里就是用一个栈来记录存入数组中的下标。
import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
List<List<Integer>> result = new ArrayList<List<Integer>>();
List<Integer> item = new ArrayList<Integer>();
Stack<Integer> indexes = new Stack<Integer>();
for(int i=0,sum=0;i<candidates.length||!indexes.empty();){
if(i<candidates.length){
while(sum+candidates[i]<target){
sum += candidates[i];
indexes.push(i);
item.add(candidates[i]);
}
if(sum+candidates[i]==target){
List<Integer> item1 = new ArrayList<Integer>(item);
item1.add(candidates[i]);
result.add(item1);
}
}
if(indexes.empty()) return result;
i = indexes.pop();
sum -= candidates[i++];
item.remove(item.size()-1);
}
return result;
}
}
Solution3
- 这道题实际和找零钱问题本质上是一样的,而找零钱是一个典型的动态规划的解法,因此本题可以用动态规划来解
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
ArrayList<List<Integer>> result = new ArrayList<List<Integer>>();
if(candidates.length==0) return result;
result.add(new ArrayList<Integer>());
HashMap<Integer,List<List<Integer>>> dp = new HashMap<Integer,List<List<Integer>>>();
dp.put(0,result);
Arrays.sort(candidates);
for(int sum=candidates[0];sum<=target;sum++){
result = new ArrayList<List<Integer>>();
for(int i=candidates.length-1;i>=0;i--){
if(!dp.containsKey(sum-candidates[i])) continue;
for(List<Integer> item:dp.get(sum-candidates[i])){
if(item.size()>0&&candidates[i]<item.get(item.size()-1)) continue;//只将升序的序列加入,解决序列重复问题
ArrayList<Integer> temp = new ArrayList<Integer>(item);
temp.add(candidates[i]);
result.add(temp);
}
if(i == candidates.length-1) dp.remove(sum-candidates[i]);//将不再需要的去掉,更节省空间
}
if(!result.isEmpty()) dp.put(sum,result);
}
return dp.get(target)==null?new ArrayList<List<Integer>>():dp.get(target);
}
}