题目描述:给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target
的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
算法分析:
题目要求中说明每个数字在每个组合中只能使用一次,所以在递归的时候,需要改变递归数组的下标,从此处的下一个位置开始递归。
同时该过程也会发生重复现象,所以需要剪枝。
在图中可以看出,黄色阴影部分最上面的那个2的左边一个分支处理的也是2,因为左边一个分支,处理的范围更大,所以黄色阴影部分的所以情况在前一个分支都会被递归出来,所以黄色部分需要剪枝
具体处理
if (i > start && candidates[i] == candidates[i - 1]) {
continue;
}
java实现代码
class Solution{
List<List<Integer>> lists = new ArrayList<>();
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
if (candidates == null || candidates.length == 0 || target < 0) {
return lists;
}
Arrays.sort(candidates);
process(0, candidates, target, new ArrayDeque<>());
return lists;
}
private void process(int start, int[] candidates, int target, Deque<Integer> path) {
//递归的终止条件
if (target < 0) {
return;
}
if (target == 0) {
lists.add(new ArrayList<>(path));
} else {
for (int i = start; i < candidates.length; i++) {
if(target-candidates[i]<0)
return ;
if (i > start && candidates[i] == candidates[i - 1]) {
continue;//去除重复情况
}
path.addLast(candidates[i]);
//因为每个数字只可以使用一次,所以递归从下一个元素开始
process(i+1, candidates, target - candidates[i], path);
path.removeLast();
}
}
}
}
本文思路来自于leetcode精选题解