一、题目描述
给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
二、解题
DFS解法
回溯算法,这题有点区别,就是每个数字只能出现一次,所以需要进行剪枝,首先将数组进行排序。全排列使用DFS,终止条件就是判断target是否小于0,然后将每一次的结果保存在res中,由于数字组合只能出现一次,所以需要判断当前值和前一个值是否相等,并且使用visited数组来保存是否遍历过。
class Solution {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
//这题的区别是每个数字只能使用一次
List<List<Integer>> res = new ArrayList<>();
List<Integer> per = new ArrayList<>();
boolean[] visited = new boolean[candidates.length];
Arrays.sort(candidates);
dfs(res,per,candidates,target,0,visited);
return res;
}
public void dfs(List<List<Integer>> res,List<Integer> per,int[] candidates,int target,int index,boolean[] visited){
//终止条件
if(target <= 0){
res.add(new ArrayList<>(per));
return ;
}
for(int i = index;i<candidates.length;i++){
if(i>0 && candidates[i] == candidates[i-1] && visited[i-1] == false){
continue;
}
if(candidates[i] <= target){
visited[i] = true;
per.add(candidates[i]);
dfs(res,per,candidates,target-candidates[i],i+1,visited);
per.remove(per.size() - 1);
visited[i] = false;
}
}
}
}
注:
如果不加条件判断,那么这题会超出时间限制。 if(candidates[i] <= target)表示当后面的值大于target的时候,那么就舍弃,因为该数组已经升序了。