给定一个候选人编号的集合 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
1 2 3 4 5 6 7 8
| 输入: candidates = , target = 8, 输出:
|
示例 2:
1 2 3 4 5 6
| 输入: candidates = , target = 5, 输出:
|
提示:
1 <= candidates.length <= 100
1 <= candidates[i] <= 50
1 <= target <= 30
本题的难点在于:集合(数组candidates)有重复元素,但还不能有重复的组合。

我在图中将used的变化用橘黄色标注上,可以看出在candidates[i] == candidates[i - 1]相同的情况下:
- used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
- used[i - 1] == false,说明同一树层candidates[i - 1]使用过
为什么 used[i - 1] == false 就是同一树层呢,因为同一树层,used[i - 1] == false 才能表示,当前取的 candidates[i] 是从 candidates[i - 1] 回溯而来的。
而 used[i - 1] == true,说明是进入下一层递归,取下一个数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Solution { List<List<Integer>> res = new ArrayList<>(); List<Integer> path = new ArrayList<>(); boolean[] used;
public List<List<Integer>> combinationSum2(int[] candidates, int target) { used = new boolean[candidates.length]; Arrays.fill(used, false); Arrays.sort(candidates); backtracking(candidates, target, 0, 0); return res; }
public void backtracking(int[] candidates, int target , int index, int sum){ if(sum == target){ res.add(new ArrayList<>(path)); return; }
for(int i = index; i < candidates.length; i++){ if(sum + candidates[i] > target) continue; if(i > index && candidates[i] == candidates[i-1] && used[i-1] == false) continue; used[i] = true; path.add(candidates[i]); backtracking(candidates, target, i+1, sum + candidates[i]); used[i] = false; path.remove(path.size()-1); } }
}
|
- 时间复杂度: $O(n * 2^n)$
- 空间复杂度: $O(n)$
使用 i >index 去重,可以不用used数组,因为只要i大于index必定是同一层的其他数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Solution { List<List<Integer>> res = new ArrayList<>(); List<Integer> path = new ArrayList<>(); int sum = 0;
public List<List<Integer>> combinationSum2(int[] candidates, int target) { Arrays.sort(candidates); backtracking(candidates, target, 0); return res; }
public void backtracking(int[] candidates, int target , int index){ if(sum == target){ res.add(new ArrayList<>(path)); return; }
for(int i = index; i<candidates.length; i++){ if(sum + candidates[i] > target) continue; if(i > index && candidates[i] == candidates[i-1]) continue; path.add(candidates[i]); sum += candidates[i]; backtracking(candidates, target, i+1); sum -= candidates[i]; path.remove(path.size()-1); } }
|