题目
Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target.
The same repeated number may be chosen from candidates unlimited number of times.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
我的想法
这个题目必须枚举才能求解,因此,可以用backtrack。不过每次用backtrack都心惊胆战的,生怕写错。以后需要把常用的算法整理出自己的模版,隔两天就练一练
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> ls = new ArrayList<>();
backtrack(candidates, new ArrayList<Integer>(), ls, 0, 0, target);
return ls;
}
private void backtrack(int[] candidates, List<Integer> temp, List<List<Integer>> ls, int start, int count, int target) {
if(count == target) {
ls.add(new ArrayList<Integer>(temp));
return;
}
for(int i = start; i < candidates.length; i++) {
//因为输入是有序数组,如果此时已经大于target,后面也无需遍历了
if(count + candidates[i] > target) continue;
temp.add(candidates[i]);
count += candidates[i]; //temp每添加一个新的元素,计入count
backtrack(candidates, temp, ls, i, count, target);
count -= temp.remove(temp.size() - 1); //每删除一个元素,也需从count中减去其值
}
}
}
因为累加法是在之前的结果上做加法,所以必须把前面的结果都存下来,对于需要输出所有结果的题来说是可以的。但在这里只需要特定的结果,如果使用累加法还需要耗费额外的空间存储之前的结果
解答
leetcode soluton: DP
这个问题可以看作一个背包问题,存储对于每一个小于等于target的数的解答。
理解cands[j] <= l.get(0)
:
假设[2,3] target = 5,则
1: null
2: [2]
3: [3]
4: [2,2]
5: [2,3]
如果没有这个判断,当cands[j] = 3
时,会重复输出[3,2]
public class Solution {
public List<List<Integer>> combinationSum(int[] cands, int target) {
Arrays.sort(cands);
//最外层的list存储每一个小于target的数的解答
List<List<List<Integer>>> dp = new ArrayList<>();
for (int i = 1; i <= target; i++) { //每一个小于target的数的组合方式都要解出来
List<List<Integer>> iList = new ArrayList();
for (int j = 0; j < cands.length && cands[j] <= i; j++) {
//如果当前的数cands[j]就是当前求解的i(不一定是目标target),
//单独创建一列,不需要循环
if (i == cands[j]) iList.add(Arrays.asList(cands[j]));
//当前所需差值 = 当前求解数i - 被遍历到的cands[j],
//因为数组从0开始存储需-1
else for (List<Integer> l : dp.get(i-cands[j]-1)) {
//滤去重复项
if (cands[j] <= l.get(0)) {
List cl = new ArrayList<>();
cl.add(cands[j]); cl.addAll(l);
iList.add(cl);
}
}
}
dp.add(iList);
}
return dp.get(target-1);
}
}