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:
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] ]
这道题和前一题很像,只不过这题的数组里面的数只能用一次,而且会有重复。
我本来采用跟上一题一样的算法,代码都快写好了,又想到了一个更简便更直观的,就是正宗的回溯,感觉上一题的不够成熟,有点难读。
此题数组里重复数字,带来一个问题就是会得到重复的List,我之前的想法是用Set来去除重复,经过检验会大大拖慢速度,需要在算法中改进。后来百度了一下看了别人的代码,发现假设如果数组里有多个1的话,那么将第一个1放入list之后回溯会得到所有包含这个1的情况,那么就不再需要将后面的1再放入数组中再回溯了,从而去除了重复的情况。比如数组为[1,1,1,1,2],目标是3,那么将第一个1放入list后回溯,变成[1,1,1,2],目标是2,会得到两个数组[1,1][2],再加上第一个1,就是[1,1,1][1,2],这包含了所有的含有1的情况,不需再考虑后面的1了,从而避免重复数组。这是比较容易理解的,实际模拟一下算法运行过程即可。
代码如下:
public class Solution {public List> combinationSum2(int[] candidates, int target) {
Arrays.sort(candidates);
List> result = new ArrayList>();
List list = new ArrayList();
combinationSum(result, list, candidates, target, 0);
return result;
}
private void combinationSum(List> result, List list, int[] candidates, int target, int index){
for(int i = index; i < candidates.length; i++){
int temp = candidates[i];
if(temp == target){
list.add(temp);
result.add(new ArrayList(list));
list.remove(list.size()-1);
break;
}
if(candidates[i] < target){
list.add(candidates[i]);
combinationSum(result, list, candidates, target - temp, i + 1);
list.remove(list.size()-1);
while(i < candidates.length-1 && candidates[i] == candidates[i+1]){
i++;
}
}
if(temp > target){
break;
}
}
}}