class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(candidates);
dfs(candidates, target, 0, res, new ArrayList<Integer>());
return res;
}
private void dfs(int[] candidates, int remainSum, int pos, List<List<Integer>> res, List<Integer> path) {
if (remainSum == 0 || pos == candidates.length) {
if (remainSum == 0) {
res.add(new ArrayList<Integer>(path));
}
return;
}
// 从pos开始往后的所有candidates中选择一个作为该层递归所选择的元素, 注意去重,只选择重复元素序列的第一个
for (int i = pos; i < candidates.length; ++i) {
if (i > pos && candidates[i - 1] == candidates[i]) continue; // 去重
if (candidates[i] > remainSum) break; // 因为已经从小到大排序,如果 ith 不满足,后面都不满足
path.add(candidates[i]);
dfs(candidates, remainSum - candidates[i], i + 1, res, path); // 注意下一层的 pos 是 i+ 1
path.remove(path.size() - 1);
}
}
} {}(1,1,2)
/ \
{}(1,2) {1}(1,2)
/ \ / \
{}(2) {1}(2) {1}(2) {1,1}(2)
/ \ / \ / \ / \
{}() {2}() {1}() {1,2}() {1}() {1,2}() {1,1}() {1,1,2}() {}(1,1,2)
/ -------|--------- \ \
{1}(1,2) | {1}(2) | {2}() {}()
/ | \ | / \ |
{1,1}(2) {1,2}() {1}() | {1,2}() {1}()|
/ \ ----------------- 这一支可以剪掉
{1,1,2}() {1,1}() 结果必然重复
每次进入下层递归会先check当前路径,这个操作相当于是在该层一个数字都不选,即为上图中每层的空元素。