非常典型的回溯法的排列数问题
x数组还是存解的下标,但是初始化的方式和子集树不一样
和39题区分开来
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
int t=0;
int sum=0;
//先排序,这样方便后面去重
Arrays.sort(candidates);
//x保存解的路径。
int []x=new int[candidates.length];
//解初始化为顺序解
for(int i=0;i<candidates.length;i++)
x[i]=i;
List<List<Integer>> res=new ArrayList<>();
backtrack(t,candidates,target,sum,x,res);
return res;
}
private void backtrack(int t,int[] candidates, int target,int sum,int[]x,List<List<Integer>> res){
if(t==candidates.length)return;
for(int i=t;i<candidates.length;i++){
if(sum+candidates[i]<=target){
//把x[i] x[t]交换的意思就是取x[t]=i;
//我一开始总写x[t]=i;再交换。怪不得疯狂出错。
Swap(x,i,t);
sum+=candidates[i];
if(sum==target){
List<Integer> oneRes=new ArrayList<Integer>();
//如果sum==target,说明从树根到这一层就是一个可行解了。故j小于等于t。
for(int j=0;j<=t;j++){
oneRes.add(candidates[x[j]]);
}
//这里是去重操作
int flag=1;
//因为原数组有重复,所以非递减的结果也可能会重复
if(res.contains(oneRes))flag=0;
for(int j=1;j<oneRes.size();j++){
//如果递减说明重复了,例如1,2,5和5,2,1
if((int)oneRes.get(j)<(int)oneRes.get(j-1))flag=0;
}
if(flag==1)
res.add(oneRes);
}
backtrack(t+1,candidates,target,sum,x,res);
//回溯
sum-=candidates[i];
Swap(x,i,t);
}
}
}
//java没有传地址这一说,所以只能把整个x数组都传过去,再交换才行。
private void Swap(int []x,int a,int b){
int temp;
temp=x[a];
x[a]=x[b];
x[b]=temp;
}
}
先存一下这个总结贴: