题目描述
给出一组候选数\ C C 和一个目标数\ T T,找出候选数中起来和等于\ T T 的所有组合。
\ C C 中的每个数字在一个组合中只能使用一次。
注意:
给出一组候选数C 和一个目标数T,找出候选数中起来和等于T的所有组合。C中的每个数字在一个组合中只能使用一次。
注意:
题目中所有的数字(包括目标数\ T T )都是正整数
组合中的数字 (a_1, a_2, … , a_ka)要按非递增排序 (a_1<=a_2<= …<=a_ka )
结果中不能包含重复的组合
组合之间的排序按照索引从小到大依次比较,小的排在前面,如果索引相同的情况下数值相同,则比较下一个索引。
示例1
输入:[100,10,20,70,60,10,50],80
返回值:[[10,10,60],[10,20,50],[10,70],[20,60]]
说明:给定的候选数集是[100,10,20,70,60,10,50],目标数是80
代码思路
在一堆数字中找到符合某个条件的多个组合,且不重复,这种题的解法除了dfs回溯好像没有更好的方式了,得所有得情况都遍历,然后再判断哪些情况是可以跳过得,由于的出来得组合示例中是递增得(但不知道为何题目描述中又说非递增,然后组合间得排序规则示例也不满足,我没按索引排序也能通过,不知道为啥,可能是描述出错了??),所以得先给数组排个序,这里直接用Arrays.sort()直接排,应该没关系吧?毕竟这个题重点不是考排序算法,于是下面给出排举得思路:
假设已经排好序得情况下,数组为[10,10,20,50,60,70,100],80
那么我们就得先从第一个数字10开始,进行最深路径算法搜索,直到满足条件的最深为止,然后再逐步回溯,
10,10,20,50 …
10 10 50 60
10 10 60
10 20 50
10 50 60
10 60 70
10 70
10 100
第二个数字
以下结果跟上面的重复了。要跳过
10,20,50 符合
10,50,60 不符合退出
10,60,70 不符合 退出
10 70
10 100
第三个数字
20 50 60
20 60
20 70
20 100
第四个数字
50 60
50 70
50 100
第五个数字
60 70
60 100
第六个数字
100
代码实现
import java.util.*;
public class Solution {
//测试用例
//[],2 [100,10,20,70,60,10,50],80 [100,30,20,70,60,10,50],80 [100,10,50],80
public ArrayList<ArrayList<Integer>> combinationSum2(int[] num, int target) {
ArrayList<ArrayList<Integer>> res=new ArrayList<ArrayList<Integer>>();
ArrayList<Integer> list=new ArrayList<Integer>();
//因为结果集要从小到大排序,所以先给数组排个序
Arrays.sort(num);
dfs(0,num,target,list,res);
return res;
}
public void dfs(int start,int[] num,int target,ArrayList<Integer> list,ArrayList<ArrayList<Integer>> res){
if(target==0){
res.add(new ArrayList(list));
}
if(start>num.length){
return;
}
for(int i=start;i<num.length;i++){
if(i>start&&num[i]==num[i-1]) continue;
if(target>=num[i]){
list.add(num[i]);
dfs(i+1,num,target-num[i],list,res);
//不管是找到了还是没找到,都需要回溯一步,所以这里需要把末尾删掉
list.remove(list.size()-1);
}
}
}
}