541 字
3 分钟
组合总和

题目描述#

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

解题思路#

  1. 回溯框架:递归遍历候选数组,维护当前组合路径和剩余目标值。
  2. 剪枝优化
    • 排序候选数组,当剩余值 < 当前候选数 时终止分支。
    • 避免重复解:递归时从当前索引开始(允许重复选自身,但不回溯选前元素)。
  3. 终止条件
    • 剩余值 =0:保存有效组合。
    • 剩余值 <0:放弃当前路径。

关键洞察#

  1. 重复选取机制:递归时索引不变可重复选同一元素,但禁止回溯start=i 而非 i+1)避免顺序不同导致的重复解。
  2. 剪枝核心排序后可提前终止无效分支(剩余值 < candidates[i] 时跳过后续)。
  3. 解空间特性:结果呈树形结构,每个节点代表一个选择路径。

复杂度分析#

  • 时间复杂度O(2^target)(最坏情况,如候选含 1) 实际因剪枝优化远低于此(例如候选无小数时)。
  • 空间复杂度O(target/min(candidates)) 递归栈深度由最小候选数决定(路径长度上限为 target/min_val)。

代码实现#

/**
* @param {number[]} candidates
* @param {number} target
* @return {number[][]}
*/
var combinationSum = function (candidates, target) {
const result = [];
const dfs = (candidates, start, combine, target) => {
if (target === 0) {
result.push(combine);
return;
}
if (start === candidates.length) return
dfs(candidates, start + 1, combine, target);
if (target - candidates[start] >= 0) {
dfs(
candidates,
start,
[...combine, candidates[start]],
target - candidates[start]
)
}
}
dfs(candidates, 0, [], target)
return result;
};

相似题目#

组合总和
https://website-truelovings-projects.vercel.app/posts/algorithms/组合总和/
作者
欢迎来到StarSky的网站!
发布于
2025-08-06
许可协议
CC BY-NC-SA 4.0