题目:
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
All numbers (including target) will be positive integers.
The solution set must not contain duplicate combinations.
For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
大意:
从给定数组中找到一组数字,要求这组数字之和等于target。另外,数组中的数字不允许被使用多次,但如果一开始就存在多个的话,可以使用多次。
思路:
本题与39题略有不同,但大致思路还是一样的。先给candidates数组排个序,然后dfs进行递归回溯。
需要注意的是:
1、在同一层递归树中,如果某元素已经处理并进入下一层递归,那么在这一层与该元素相同的值就应该跳过。否则将出现重复。
例如:1,1,2,3
如果第一个1已经处理并进入下一层递归1,2,3
那么在本次递归中的第二个1就应该跳过,因为后续所有情况会被上一行的计算覆盖掉。
2、相同元素第一个进入下一层递归,而不是任意一个
例如:1,1,2,3
如果第一个1已经处理并进入下一层递归1,2,3,那么两个1是可以同时成为可行解的。
而如果选择的是第二个1并进入下一层递归2,3,那么不会出现两个1的解了。这里只需要对candidates数组排好序后按顺序访问即可。
代码:
public class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
List<Integer> current = new ArrayList<Integer>();
Arrays.sort(candidates);
combinationSum2(result, current, 0, candidates, target);
return result;
}
private void combinationSum2(List<List<Integer>> result, List<Integer> current, int start, int[] candidates, int target) {
//找到一组可行解,放入result中
if(target == 0) {
List<Integer> temp = new ArrayList<Integer>(current);
result.add(temp);
return;
}
//prev保证在同一层内,不会使用相同值得元素,从而避免求出重复值
int prev = 0;
for(int i = start; i < candidates.length; i++) {
if(target < candidates[i]) {
return;
}
//与上次访问的元素不相等
if(prev != candidates[i]) {
current.add(candidates[i]);
combinationSum2(result, current, i + 1, candidates, target - candidates[i]);
//退回上一层递归,把在之前递归层里放入的元素去掉
current.remove(current.size() - 1);
prev = candidates[i];
}
}
}
}