
- 39题衍生题,39题基础上,加了一个条件,candidates数组中每个数字在同一个组合中只能使用一次。这些数字是有可能相同的。
- 这道题的难点在于,[1,7,1,6]为例,[1,1,6],[1,7],[7,1]都满足target = 8的条件,但是返回结果中不能同时返回[1,7]和[7,1]因为这两个组合是同一个,是重复的。
- 所以我们先将数组排序为[1,1,6,7],当我们某个位置枚举时,如果和上次一样就跳过
- 例如,我们第一个位置先选用[1,
1
,6,7]标黄的1,枚举出[1,1
,6],[1,7],此时这个1就毕业了,它会腾出第一个位置 - 不跳过的情况下:我们第一个位置会直接用第二个位置的
1
,从而枚举出[1
,7]. 此时就会枚举出两个相同的组合[1,7]和[1
,7] - 但是,现在我们,要切换下一个值来当前位置时。先比较下一个值是否和当前值一样,如果一样就跳过。从而不再次枚举[1,7]。
- 我们发现1 =
1
,所以我们跳过这个1
.然后继续判断比较后面的值6,发现不一样,那么下次就用6在第一个位置枚举
整个代码,与39题代码的唯一区别,就是增加了先排序,然后相同位置,如果下次枚举还是一样的值,就跳过的逻辑 |
---|
与39题代码唯二不一样的地方如下:
1. 实现方式1:典型回溯
- 仅仅修改了39题的代码,增加了两行代码

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
public class Solution {
int[] candidates;
int target;
int length;
List<List<Integer>> lists;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
this.candidates = candidates; this.target = target; this.length = candidates.length;
this.lists = new ArrayList<List<Integer>>();
Integer[] records = new Integer[length];
backTracking(records,0,0,0);
return lists;
}
public void backTracking(Integer[] records,int row,int sum,int index){
if(index >=length) return;
else if(sum > target)return;
else{
records[row] = candidates[index];
int curSum = sum+records[row];
if(curSum>target) return;
if(curSum == target) {
List<Integer> list = new ArrayList<>();
for(int i = 0;i<=row;i++) list.add(records[i]);
lists.add(list);
}else{
backTracking(records,row+1,curSum,index+1);
}
while(index<length-1 && candidates[index]==candidates[index+1]) index++;
backTracking(records,row,sum,index+1);
}
}
}
2. 实现方式2:模拟树的深度优先遍历
- 此方式,将回溯算法,当成树来进行深度遍历。

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
public class Solution {
int[] candidates;
int len;
List<List<Integer>> res;
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
this.len = candidates.length;
res = new ArrayList<>();
if (len == 0) return res;
Arrays.sort(candidates);
this.candidates = candidates;
Deque<Integer> path = new ArrayDeque<>(len);
dfs(target,0,path);
return res;
}
private void dfs(int target,int begin, Deque<Integer> path) {
if (target == 0) {
res.add(new ArrayList<>(path));
return;
}
for (int i = begin; i < len; i++) {
if (target - candidates[i] < 0) break;
if (i > begin && candidates[i] == candidates[i - 1]) continue;
path.addLast(candidates[i]);
dfs(target - candidates[i],i + 1, path);
path.removeLast();
}
}
}