组合总和
2024年12月5日大约 2 分钟教学文档回溯法
组合总和
1. 题目描述
给你一个无重复元素的整数数组 candidates
和一个目标整数 target
,找出 candidates
中可以使数字和为目标数 target
的所有不同组合,并以列表形式返回。你可以按任意顺序返回这些组合。candidates
中的同一个数字可以无限制重复被选取。如果至少一个数字的被选数量不同,则两种组合是不同的。对于给定的输入,保证和为 target
的不同组合数少于 150 个。
示例 1
输入:candidates = [2,3,6,7]
, target = 7
输出:[[2,2,3],[7]]
解释:2 和 3 可以形成一组候选,2 + 2 + 3 = 7。注意 2 可以使用多次。7 也是一个候选,7 = 7。仅有这两种组合。
示例 2
输入:candidates = [2,3,5]
, target = 8
输出:[[2,2,2,2],[2,3,3],[3,5]]
示例 3
输入:candidates = [2]
, target = 1
输出:[]
2. 分析
可以通过回溯法来解决。我们需要找到所有可能的组合,使得这些组合的和等于目标值 target
。由于每个数字可以无限制重复使用,在回溯过程中需要特别注意这一点。
- 创建一个结果列表
result
,用于存储所有满足条件的组合。创建一个路径列表path
,用于记录当前正在构建的组合。 - 定义一个递归函数
backtrack
,该函数接受三个参数:当前剩余的目标值target
,当前路径path
,以及当前选择的起始索引start
。- 终止条件:
- 如果
target = 0
,说明当前路径是一个有效的组合,将其添加到结果列表result
中。 - 如果
target < 0
,说明当前路径不可能是一个有效的组合,直接返回。
- 如果
- 选择列表:
- 遍历从
start
开始的每个候选数字,将当前数字加入到路径path
中。 - 递归调用
backtrack
,传入更新后的target
和path
,以及当前选择的索引start
(允许重复选择同一个数字)。 - 撤销选择,将当前数字从路径
path
中移除,继续尝试其他选择。
- 遍历从
- 终止条件:
- 返回结果列表
result
。
3. 代码
public class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> result = new ArrayList<>();
backtrack(candidates, target, 0, new ArrayList<>(), result);
return result;
}
private void backtrack(int[] candidates, int target, int start, List<Integer> path, List<List<Integer>> result) {
if (target == 0) {
result.add(new ArrayList<>(path));
return;
}
if (target < 0) {
return;
}
for (int i = start; i < candidates.length; i++) {
path.add(candidates[i]);
backtrack(candidates, target - candidates[i], i, path, result);
path.remove(path.size() - 1);
}
}
}