给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
- 所有数字(包括
target
)都是正整数。 - 解集不能包含重复的组合。
示例 1:
输入: candidates =[2,3,6,7],
target =7
, 所求解集为: [ [7], [2,2,3] ]
示例 2:
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
去重复
在搜索的时候,需要设置搜索起点的下标 begin ,由于一个数可以使用多次,下一层的结点从这个搜索起点开始搜索;
在搜索起点 begin 之前的数因为以前的分支搜索过了,所以一定会产生重复。
剪枝提速
如果一个数位搜索起点都不能搜索到结果,那么比它还大的数肯定搜索不到结果,基于这个想法,我们可以对输入数组进行排序,以减少搜索的分支;
排序是为了提高搜索速度,非必要;
搜索问题一般复杂度较高,能剪枝就尽量需要剪枝。把候选数组排个序,遇到一个较大的数,如果以这个数为起点都搜索不到结果,后面的数就更搜索不到结果了。
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
class Solution {
public static List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> list = new ArrayList<List<Integer>>();
Arrays.sort(candidates);
def(new ArrayDeque<>(), 0, 0, target, candidates, list);
return list;
}
/**
* @param candidates 数组输入
* @param now 当前值
* @param target 目标值
* @param begin 本轮搜索的起点下标
* @param path 从根结点到任意结点的路径
* @param list 结果集变量
*/
private static void def(Deque<Integer> path, int begin, int now ,int target, int[] candidates ,List<List<Integer>> list) {
if(now == target) {
list.add(new ArrayList<Integer>(path));
return;
}
for (int i = begin ; i < candidates.length ; i++) {
//剪枝
if(now + candidates[i] > target) {
break;
}
path.addLast(candidates[i]);
def(path , i ,now + candidates[i] ,target ,candidates ,list);
path.removeLast();
}
}
}