给定一个数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用一次。
说明:
- 所有数字(包括目标数)都是正整数。
- 解集不能包含重复的组合。
譬如:输入candidates = [10,1,2,7,6,1,5] ,target = 8,
所求解集为:
[
[1,7],[1,2,5],[2,6],[1,1,6]
]
我的思路:
采用回溯法,先将数组排序,从头开始遍历数组,对于每个元素,有两种选择,要么加入list,要么不加入list,由此形成一棵解空间树,如果累加值大于target则“剪枝”,不再遍历其子节点,否则继续遍历,当累加值等于target时,添加到结果集中。
我的代码:
public class CombinationSum2 {
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
if(candidates.length == 0 || (candidates.length == 1 && candidates[0]<target))
return res;
Arrays.sort(candidates);
combination(res, null, target, 0, candidates);
return res;
}
private void combination(List<List<Integer>> res, List<Integer> tmp, int target,int i,int[] candidates) {
if(target == 0) {
List<Integer> tmp1 = new ArrayList<>(tmp);
if(!res.contains(tmp1)) //尚无该结果,加入
res.add(tmp1);
return;
}else if(target<0) {
tmp.remove(tmp.size()-1);
return;
}
if(i>=candidates.length)return; //已经遍历完数组了,结束
if(candidates[i]>target)return; //如果下一个值大于target则无需继续遍历
if(tmp == null) tmp = new ArrayList<>();
tmp.add(candidates[i]);
//加入
combination(res, tmp, target-candidates[i], i+1, candidates);
tmp.remove(tmp.size()-1);
//不加入
combination(res, tmp, target, i+1, candidates);
}
public static void main(String[] args) {
System.out.println(new CombinationSum2().combinationSum2(new int[] {
10,1,2,7,6,1,5
}, 8));
System.out.println(new CombinationSum2().combinationSum2(new int[] {
2,5,2,1,2
}, 5));
}
}