题目描述
// 39. 组合总和
// 给定一个无重复元素的数组 candidates 和一个目标数 target ,
// 找出 candidates 中所有可以使数字和为 target 的组合。
// candidates 中的数字可以无限制重复被选取。
// 说明:
// 所有数字(包括 target)都是正整数。
// 解集不能包含重复的组合。
题解
// 回溯搜索法
// 同类方法里一个很好的题目。
// 构建答案保存位res用于保存List,构建数字组合保存List combination,
// 递归调用backtracking,输入候选人数组nums,目标数target,答案保存位res,
// 数字组合保存List combination,以及回溯搜索的搜索起点索引,初始化为0。
// 最后返回res。
//
// 下面来定义回溯搜索函数backtracking,函数输入为候选人数组nums,目标数target,
// 答案保存位res,数字组合保存List combination,回溯搜索的搜索起点索引start。
// 老样子,递归函数,先写递归终止条件,是当target为0时(因为后面要用target减去
// 候选数来更新下一次搜索的target),说明搜索的组合符合条件,将combination中
// 元素用ArrayList包装存入res中,return脱离递归,向上回溯。
//
// for循环从搜索起始点start开始一直遍历到nums的尾部,遍历值为nums[i],
// 如果nums[i]小于等于target,说明可能可以构成组合,将nums[i]暂存入combination,
// 递归调用backtracking,由于nums[i]已经被算入数字和中,所以target-nums[i]
// 为下一次搜索的target,搜索起点索引设置为for循环的当前遍历位i。
// 如果递归回来,则说明刚刚放入的nums[i]的情况已经经过排查,此时在combination中
// 去除刚刚存入的nums[i],然后for循环会继续遍历下一个nums[i],重复刚刚的操作。
//
// 执行用时:2 ms, 在所有 Java 提交中击败了99.93%的用户
// 内存消耗:38 MB, 在所有 Java 提交中击败了99.98%的用户
class Solution {
public List<List<Integer>> combinationSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> combination = new ArrayList<>();
backtracking(nums, target, res, combination, 0);
return res;
}
private void backtracking(int[] nums, int target, List<List<Integer>> res, List<Integer> combination, int start) {
if (target == 0) {
res.add(new ArrayList<>(combination));
return;
}
for (int i = start; i < nums.length; i++) {
if (nums[i] <= target) {
combination.add(nums[i]);
backtracking(nums, target - nums[i], res, combination, i);
combination.remove(combination.size() - 1);
}
}
}
}