1. 问题背景与核心需求Combination Sum组合总和是LeetCode上经典的回溯算法问题编号为第39题。给定一个无重复元素的整数数组candidates和一个目标整数target要求找出所有candidates中数字的组合使得这些数字之和等于target。每个数字可以被无限次重复使用最终返回这些唯一组合的列表。这个问题在技术面试中出现频率极高尤其是在考察候选人递归思维和剪枝优化能力时。我在准备算法面试时发现超过60%的互联网公司二面都会考察此类回溯问题。下面通过一个具体案例说明给定 candidates [2,3,6,7], target 7 解集为 [ [2,2,3], [7] ]2. 算法设计思路解析2.1 回溯算法框架选择采用回溯算法解决此问题的原因在于需要枚举所有可能的组合情况决策树遍历组合中的元素可重复使用与子集问题区别需要避免重复解顺序不同但元素相同的组合回溯模板的三要素在此问题中表现为选择列表当前可选的candidates元素路径已选择的数字组合结束条件路径和等于target或超过target2.2 关键优化策略2.2.1 排序预处理candidates.sort() # 先排序便于后续剪枝排序后可以实现提前终止无效搜索当当前和候选[i] target时后续更大元素必然无效避免生成顺序不同但元素相同的重复解2.2.2 索引控制每次递归从当前索引开始而非0这是与全排列问题的本质区别for i in range(start, len(candidates)): backtrack(..., i, ...) # 不是i13. 完整实现与逐行解析3.1 Python标准解法def combinationSum(candidates, target): def backtrack(start, path, remaining): if remaining 0: res.append(path[:]) return for i in range(start, len(candidates)): num candidates[i] if num remaining: break # 剪枝 path.append(num) backtrack(i, path, remaining - num) path.pop() # 回溯 candidates.sort() res [] backtrack(0, [], target) return res3.2 关键代码段说明递归终止条件remaining 0时记录有效解剪枝优化if num remaining: break提前终止无效分支回溯操作path.pop()撤销最后选择尝试其他可能性索引控制backtrack(i,...)保证元素可重复使用但不会产生顺序不同的重复解4. 复杂度分析与优化对比4.1 时间复杂度最坏情况O(N^(T/M1))其中N是candidates数量T是targetM是最小候选数实际运行通过剪枝可大幅减少递归深度4.2 空间复杂度递归栈深度O(T/M)结果存储空间取决于解的数量4.3 与变种问题对比问题变种区别点解法调整Combination Sum II元素不可重复使用backtrack(i1,...)Combination Sum III指定组合长度和范围增加长度限制条件Combination Sum IV考虑顺序不同的解动态规划解法更优5. 常见错误与调试技巧5.1 典型报错场景重复解问题错误表现得到[2,2,3]和[2,3,2]等重复组合解决方法保持索引单向移动使用start参数无限递归问题错误表现栈溢出检查点确保remaining递减终止条件正确5.2 调试打印技巧在backtrack函数开头添加print(fStart:{start}, Path:{path}, Remaining:{remaining})典型输出示例Start:0, Path:[], Remaining:7 Start:0, Path:[2], Remaining:5 Start:0, Path:[2,2], Remaining:3 Start:0, Path:[2,2,2], Remaining:1 # 剪枝发生 Start:1, Path:[2,2], Remaining:3 # 回溯后尝试36. 实际面试中的扩展问题6.1 面试官可能追问如何优化解集存储空间使用生成器替代列表存储及时释放不再使用的中间结果如果candidates包含负数如何处理需要额外终止条件如设置最大深度可能产生无限组合如[-1,1]与target0如何改为求组合数量而非具体组合转换为动态规划问题类似硬币找零6.2 白板编码注意事项先明确输入输出示例画出决策树示意图强调剪枝优化点讨论边界情况空数组、target0等7. 同类问题刷题建议按照难度梯度练习入门Subsets (78), Permutations (46)进阶Combination Sum II (40), Palindrome Partitioning (131)挑战Word Search II (212), N-Queens (51)建议搭配使用LeetCode的Playground功能可视化观察递归调用过程。我在刷题时发现对于target8的case通过打印决策树可以直观看到剪枝减少约40%的递归调用。