
/**
从数组中选取若干元素和为指定值,元素可重复选取
大致执行流程(for循环 + 递归):
首先选取第一个元素添加到temp中,后续重复选择该元素,直到sum>=target
回溯,回退temp状态,重复选择下一个元素,直到sum>=target
回溯......,直到以当前元素开始的所有情况都处理完毕
从第二个元素开始选取(避免重复),重复上述流程
.......
直到从最后一个元素开始选取,执行完毕得到所有结果
本题特点:
也需要index控制可访问元素,但由于元素是可重复访问的,index并非每次递归都递增
而是与for循环中的i绑定,只有以当前元素为可重复元素情况递归完毕后,才“与i一起迭代”
细节:
index除了控制从哪个元素开始外,还控制了当前递归哪个元素被重复选择
提前对数组进行排序,可直接提前进行判断,终止必定不成立的无效分支,直接break结束当前循环
*/
class Solution {
//保存结果集
private List<List<Integer>> res = new ArrayList<>();
//保存单次结果
private List<Integer> tempResult = new ArrayList<>();
//避免重复传参
private int[] candidates;
private int target;
public List<List<Integer>> combinationSum(int[] candidates, int target) {
/**
从数组中选取若干元素和为指定值,元素可重复选取
大致执行流程(for循环 + 递归):
首先选取第一个元素添加到temp中,后续重复选择该元素,直到sum>=target
回溯,回退temp状态,重复选择下一个元素,直到sum>=target
回溯......,直到以当前元素开始的所有情况都处理完毕
从第二个元素开始选取(避免重复),重复上述流程
.......
直到从最后一个元素开始选取,执行完毕得到所有结果
本题特点:
也需要index控制可访问元素,但由于元素是可重复访问的,index并非每次递归都递增
而是与for循环中的i绑定,只有以当前元素为可重复元素情况递归完毕后,才“与i一起迭代”
细节:
index除了控制从哪个元素开始外,还控制了当前递归哪个元素被重复选择
提前对数组进行排序,可直接提前进行判断,终止必定不成立的无效分支,直接break结束当前循环
*/
this.candidates = candidates;
this.target = target;
//对数组进行排序,便于直接剔除不可能符合条件的组合
Arrays.sort(candidates);
backtrack(0,0);
return res;
}
private void backtrack(int index, int sum) {
if(sum > target) return;
if(sum == target) {
res.add(new ArrayList(tempResult));
return;
}
for(int i = index; i < candidates.length; i++) {
if (sum + candidates[i] > target) {
break; // 剪枝:因为数组已排序,后面的元素更大,无需继续
}
//保存本次添加的元素
tempResult.add(candidates[i]);
sum += candidates[i];
//下一次从i开始,只有重复选择当前元素得出结果后,回溯迭代i,才从下一个元素开始
backtrack(i, sum);
//回溯 回退sum与tempResult状态
sum -= tempResult.get(tempResult.size() - 1);
tempResult.remove(tempResult.size() - 1);
}
}
}
259



被折叠的 条评论
为什么被折叠?



