题目:和39题一样,区别在于每个数在每一组里只能使用一次
思路:
学习第39题的思路,采用递归回溯的方法
需要注意(1,2,7)和(7,2,1)其实属于同一种解,因此如果出现了第二个解的时候,要对其进行排序,排序后判断是否和第一个解一样,如果一样就不放入结果数组。
代码:
//40.组合总和II
public class Solution40 {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
//candidates中的每个数在每个组合中只能用一次
Arrays.sort(candidates);
List<List<Integer>> resList = new ArrayList<>();
List<Integer> list = new ArrayList<>();
find(candidates, target, 0, list, resList);
return new ArrayList<>(resList);
}
//从下标i开始找target,可以用i位置的数,也可以不用,当target为0时,递归结束
public void find(int[] candidates, int target, int i, List<Integer> list, List<List<Integer>> resList) {
if (target == 0) {
//***判断是否已有,比如(1,7)和(7,1)不能同时存在
//由于按照递归+有序数组的方式,必然前小后大,所以这里先排序再插入
//不能这么干,因为HashSet判断是否重复依据的是地址,而不是内容。
List<Integer> list1 = new ArrayList<>(list);
Integer arr[] = new Integer[list1.size()];
list1.toArray(arr);
Arrays.sort(arr);
//判断是否已有
boolean yiyou = false;
for (List<Integer> lis : resList) {
Integer arrT[] = new Integer[list1.size()];
lis.toArray(arrT);
if (arr.length != arrT.length)
continue;
int p;
for (p = 0; p < arrT.length; p++) {
if (arr[p] != arrT[p])
break;
}
if (p == arrT.length) {
yiyou = true;
break;
}
}
if (!yiyou)
resList.add(list1);
return;
}
if (target < 0 || i == candidates.length) {
return;
}
//用i位置的数
list.add(candidates[i]);
find(candidates, target - candidates[i], i + 1, list, resList);
//用完以后去掉1个数(最后一次添加的数)
list.remove(list.size() - 1);
//不用i位置的数
find(candidates, target, i + 1, list, resList);
}
public static void main(String[] args) {
Solution40 s40 = new Solution40();
s40.combinationSum2(new int[]{2,5,2,1,2}, 5);
}
}