39_组合总和[MEDIUM]
约 536 字大约 2 分钟
2026-03-24
给你一个 无重复元素 的整数数组 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
输出: []解题思路
- 先排序,以便后续剪枝减少计算量
- 每凑一个数字,target 变小,将剩余要凑的数用 remainTarget 表示
- 回溯终止条件:当
remainTarget == 0时,说明找到了一个组合,将其加入到结果列表中并结束当前递归分支。 - 回溯单层搜索逻辑:
- 遍历 candidates 数组,从 startIndex 开始。
- 如果当前数字大于 remainTarget,由于数组已排序,后面的数字直接舍弃(剪枝)。
- 将当前数字加入 path。
- 递归调用自身,处理下一个数字(
remainTarget - candidates[i])。 - 回溯(撤销选择):将当前数字从 path 中移除。
Java实现
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
// 先排序,以便后续剪枝减少计算量
Arrays.sort(candidates);
trackBack(candidates, target, 0, res, path);
return res;
}
private void trackBack(int[] candidates, int remainTarget, int startIndex, List<List<Integer>> res, List<Integer> path){
if (remainTarget == 0){
res.add(new ArrayList<>(path));
return;
}
for (int i = startIndex; i < candidates.length; i++){
// 如果当前数字已经大于剩余目标值,由于数组已排序,后面的数字直接舍弃
if (candidates[i] > remainTarget){
break;
}
path.add(candidates[i]);
trackBack(candidates, remainTarget - candidates[i], i, res, path);
path.remove(path.size() - 1);
}
}
}