给定一个无重复元素的数组 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]
]
思路: 回溯法搜索(排列树)
step 1 : 排序
step 2 : 回溯搜索 , 将每一个可行解保存到res集合中
剪枝方案:
1.经过排序后 如 2, 3, 6 ,7
先选一个数,如果这个数加上已经在可行解中的数没有超过target 如 (sum:4)+2 <= (target:7)说明这个数有可能产生可行解(sum=target)
将其加入到可行解中(2,2,2).
如果这个数加上已经在可行解中的数超过了target 如 (sum:6)+2 <= (target:7)说明这个数已经不可能产生可行解了
2.每次选择的数都是从candidates中选择的[2,3,6,7](遍历方式,从小到大)
如果2+sum>target , 那么还有必要尝试选择3,6,7吗?显然没有必要了.
3.根据题目要求.产生的可行解也是递增的
如[2,2,3] 可以
[3,2,2] 不可以
[3,2,3] 不可以
也就是说,如果当前选择的数为3,那么下一层就不能选择2
如果当前选择的数为6,那么下一层就不能选择2,3 (通过遍历时对起始下标的控制能很好的解决这个问题)
1 class Solution39 {
2
3 int target;
4 private List<List<Integer>> res = new ArrayList<>();
5
6 public List<List<Integer>> combinationSum(int[] candidates, int target) {
7 if (candidates == null || candidates.length == 0) {
8 return res;
9 }
10 this.target = target;
11 Arrays.sort(candidates);
12 search(candidates, 0, new ArrayList<>(),0);
13 return res;
14 }
15
16 private void search(int[] candidates, int sum, List<Integer> list,int pos) {
17 if (sum <= target) {
18 if (sum == target) {
19 res.add(new ArrayList<>(list));
20 return;
21 }
22 for (int i = pos; i < candidates.length; i++) {
23 if (sum + candidates[i] <= target) {
24 list.add(candidates[i]);
25 search(candidates, sum + candidates[i], list,i);
26 list.remove((Integer) candidates[i]);
27 } else {
28 break;
29 }
30 }
31 }
32 }
33 }