一、题目
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
- 所有数字(包括 target)都是正整数。
- 解集不能包含重复的组合。
二、思路:回溯法(来自题解)
思路:
示例 1:输入: candidates = [2,3,6,7],target = 7。
- 候选数组里有 2 ,如果找到了 7 - 2 = 5 的所有组合,再加上 2 ,就是 7 的所有组合;
- 同理考虑 3,如果找到了 7 - 3 = 4 的所有组合,再加上 3 ,就是 7 的所有组合;
- 以此类推 … …
画出解空间树如下:
三、代码
代码一:
class Solution {
List<List<Integer>> res = new ArrayList<>();// 结果集
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates.length == 0)
return res;
backTrack(candidates, target, 0, new LinkedList<Integer>());
return res;
}
/**
* @param candidates 输入数组
* @param target 目标和
* @param start 本轮搜索的起点
* @param path 从根节点到任意节点的路径
*/
public void backTrack(int[] candidates, int target, int start, LinkedList<Integer> path){
if(target == 0){
res.add(new ArrayList<>(path));
return;
}
for(int i = start; i < candidates.length; i++){
if(candidates[i] <= target){
path.add(candidates[i]);
backTrack(candidates, target - candidates[i], i, path);
path.removeLast();
}
}
}
}
代码二:
我们可以先对数组进行排序,这样,当减到一个负数的时候,就不用再往后搜索了,以此设计剪枝函数减少搜索次数。
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> combinationSum(int[] candidates, int target) {
if(candidates.length == 0)
return res;
// 对数组进行排序,可以设计剪枝函数
Arrays.sort(candidates);
backTrack(candidates, target, 0, new LinkedList<Integer>());
return res;
}
/**
* @param candidates 输入数组
* @param target 目标和
* @param start 本轮搜索的起点
* @param path 从根节点到任意节点的路径
*/
public void backTrack(int[] candidates, int target, int start, LinkedList<Integer> path){
if(target == 0){
res.add(new ArrayList<>(path));
return;
}
for(int i = start; i < candidates.length; i++){
// 数组有序的前提下,剪枝
if(candidates[i] > target)
break;
path.add(candidates[i]);
backTrack(candidates, target - candidates[i], i, path);
path.removeLast();
}
}
}