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] ]
每个候选元素只能用一次,最终的结果里面不允许有重复的集合,根Combination Sum I 一样总体是排序以后回溯+规定顺序,从小到大搜寻满足条件的组合,但是候选元素本身就有可能存在重复的元素,例如这里排序之后是[1,1,2,5,6,7,10],虽然限制了从小到大取元素,每次从上次搜寻的index基础上+1再继续搜索,但是仍有可能生成重复的集合[1,2,5],第一次的1来自Index=0,第二次的1来自index=1。
那怎么处理呢?hash是下策,从产生上抑制才是优的选择,是否可以碰到重复元素,就忽略呢?例如只考虑第一个1,第二个2忽略,
这样会产生丢失解的情况,以给出的例子中的解[1,1,6],很容易发现这样处理是不妥的。解决办法应该采取把这两个1 “捆绑”的思想,限制第二个1只有当第一个1在“使用中”的时候才能够使用,而不能够单独使用,因为单独使用的效果和第一个1重复,这样避免了丢失解又不生成重复集合。
public class Solution {
boolean[] onstack;
List<List<Integer>> retlist=new ArrayList<>(64);
ArrayList<Integer> arraylist=new ArrayList<>(64);
public List<List<Integer>> combinationSum2(int[] candidates, int target)
{
int len=candidates.length;
onstack=new boolean[len];
Arrays.sort(candidates);
dfs(candidates, target, 0, -1);
return retlist;
}
public void dfs(int[] arr,int t,int sum,int lastindex)
{
if(sum>t)
return ;
if(sum==t)
{
retlist.add(new ArrayList<>(arraylist));
return ;
}
for(int i=lastindex+1;i<arr.length;i++)
{
if(i>0&&arr[i]==arr[i-1])
if(lastindex!=i-1)
continue;
if(!onstack[i])
{
onstack[i]=true;
arraylist.add(arr[i]);
dfs(arr, t, sum+arr[i], i);
arraylist.remove(arraylist.size()-1);
onstack[i]=false;
}
}
}
}