给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入:candidates=[2,3,6,7],target=7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入:candidates=[2,3,5],target=8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
题目的意思:
从1到n中随机选取几个数,让其和等于m根据这句话,选出来的数可以重复,且选取的个数任意,但是不能包含重复的组合
所以也可以利用深度优先搜索【DFS】+回溯来解决
其中深度优先搜索算法用来寻找所有可能的组合,而回溯是用来筛选出所有可能组合中的可行解【如果发现某候选解不是可行解,直接丢弃】
注:在进行深搜时,下一次深搜应从当前元素继续往后看【其中从当前元素开始继续找的话既保证了元素可以重复,又不会造成最终的组合重复】
步骤:
1.从第一个元素开始相加
2.让局部和继续累加候选的剩余值
3.局部和等于目标值,保存组合,向上回退,寻找其它组合
//深搜+回溯
public class combinationSum {
private List<List<Integer>> res = new ArrayList<>();
private List<Integer> list = new ArrayList<>();
public List<List<Integer>> combinationSum1(int[] candidates, int target) {
if (candidates == null || candidates.length == 0) {
return res;
}
backTrace(candidates, 0, target, 0);
return res;
}
private void backTrace(int[] candidates, int sum, int target, int beginIndex) {
//边界条件,如果大于等于目标值,就结束【因为此时的和已经大于或等于目标值了,再继续深搜只会让和更加大于目标值,而这样的组合明显不合题意】
if (sum >= target) {
//如果等于目标值,表示找到一种组合,放入最终集合中
if (sum == target) {
res.add(new ArrayList<>(list));
}
return;
}
for (int i = beginIndex; i < candidates.length; i++) {
//如果当前元素大于目标值,直接跳过
if (candidates[i] > target) {
continue;
}
list.add(candidates[i]);
//从当前元素开始往后看【因为元素可以重复】
backTrace(candidates, sum + candidates[i], target, i); //区别:beginIndex为当前元素的下标!!!
//回溯,向上回退,寻找下一种组合
list.remove(list.size() - 1);
}
}
//candidates = [2,3,6,7], target = 7
// 从2开始深搜:
// 2<7 -> 2+2<7 -> 2+2+2<7 -> 2+2+2+2>7【丢弃最后一个2,且不再 在2+2+2+2的基础上深搜】 -> 2+2+2+3>7【丢弃3,且不再 在2+2+2+3的基础上深搜】
// -> 2+2+2+6>7【丢弃6,且不再 在2+2+2+6的基础上深搜】 -> 2+2+2+7>7【丢弃7,且不再 在2+2+2+7的基础上深搜】
// -> 丢弃最后一个2【2+2+2的深搜完毕】
// -> 2+2+3==7【找到一种组合,存入最终结果】 -> 丢弃3【2+2+3的深搜完毕】
// -> 2+2+6>7【丢弃6,2+2+6的深搜完毕】
// -> 2+2+7>7【丢弃7,2+2+7的深搜完毕】
// -> 丢弃最后一个2【2+2的深搜完毕】
// -> 2+3<7 -> 2+3+3>7【丢弃最后一个3,且不再 在2+3+3的基础上深搜】 -> 2+3+6>7【丢弃6,且不再 在2+3+6的基础上深搜】
// -> 2+3+7>7【丢弃7,且不再 在2+3+7的基础上深搜】
// -> 丢弃3【2+3的深搜完毕】
// -> 2+6>7【丢弃6,2+6的深搜完毕】
// -> 2+7>7【丢弃7,2+7的深搜完毕】
// -> 丢弃2【2的深搜完毕】
// 从3开始深搜:
// 3<7 -> 3+3<7 -> 3+3+3>7【丢弃最后一个3,且不再 在3+3+3的基础上深搜】 -> 3+3+6>7【丢弃6,且不再 在3+3+6的基础上深搜】
// -> 3+3+7>7【丢弃7,且不再 在3+3+7的基础上深搜】
// -> 丢弃最后一个3【3+3的深搜完毕】
// -> 3+6>7【丢弃6,3+6的深搜完毕】
// -> 3+7>7【丢弃7,3+7的深搜完毕】
// -> 丢弃3【3的深搜完毕】
// 从6开始深搜:
// 6<7 -> 6+6>7【丢弃最后一个6,且不再 6+6的基础上继续深搜】 -> 6+7>7【丢弃7,且不再 6+7的基础上继续深搜】
// -> 丢弃6【6的深搜完毕】
// 从7开始深搜:
// 7==7【找到一种组合,存入最终结果】
// -> 丢弃7【7的深搜完毕】
// 数组candidates的元素已全部遍历完
//最终结果:[[2,2,3],[7]]
}