1.题目描述:
给你一个无重复元素的整数数组candidates和一个目标整数target,找出candidates中可以使数字和为目标数target的所有不同组合,并以列表形式返回。你可以按任意顺序返回这些组合。candidates中的同一个数字可以无限制重复被选取。如果至少一个数字的被选数量不同,则两种组合是不同的。对于给定的输入,保证和为target的不同组合数少于150个。
2.回溯:
class Solution {
private List<List<Integer>> resList = new ArrayList<>();
private List<Integer> list = new ArrayList<>();
private int sum = 0;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
backTracking(candidates, target, 0);
return resList;
}
public void backTracking(int[] candidates, int target, int index) {//需要index起始指针,否则将出现顺序不同但是重复的结果
if (sum > target) return;//必不可少,否则抽象树的深度或递归深度无限制
if (sum == target) {
resList.add(new ArrayList<>(list));
return;
}
for (int i = index; i < candidates.length; i++) {
list.add(candidates[i]);
sum += candidates[i];
backTracking(candidates, target, i);
list.remove(list.size() - 1);//回溯
sum -= candidates[i];//回溯
}
}
}
3.剪枝:
未剪枝前,在某次回溯中若sum已经大于target,不会立即停止,而是会进行下一次递归,在下一次递归的终止条件中被return,可以在循环中直接判断并break,但是这需要保证后面的所有元素都大于当前累加的元素,也就是需要对数组进行排序。
class Solution {
private List<List<Integer>> resList = new ArrayList<>();
private List<Integer> list = new ArrayList<>();
private int sum = 0;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);//排序
backTracking(candidates, target, 0);
return resList;
}
public void backTracking(int[] candidates, int target, int index) {
//if (sum > target) return;可以省去
if (sum == target) {
resList.add(new ArrayList<>(list));
return;
}
for (int i = index; i < candidates.length; i++) {//也可以在循环条件中加上 && sum + candidates[i] <= target
if (sum + candidates[i] > target) break;//必须先判断下次递归时会不会超过大小再后序操作,超过则深度不加,再加广度;否则将出现list一直是2222-2223-2223-2223直至结束resList为null
list.add(candidates[i]);
sum += candidates[i];
backTracking(candidates, target, i);
list.remove(list.size() - 1);
sum -= candidates[i];
}
}
}
二刷:
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
Arrays.sort(candidates);
backTracking(candidates, target, 0);
return res;
}
public void backTracking(int[] candidates, int target, int index) {
int sum = 0;
for (Integer item : list) sum += item;
if (sum == target) res.add(new ArrayList<>(list));
if (sum >= target) return;
for (int i = index; i < candidates.length && sum + candidates[i] <= target; i++) {
list.add(candidates[i]);
backTracking(candidates, target, i);//不加一可复用当前元素
list.remove(list.size() - 1);
}
}
}