面试知识库

39. 组合总和#

今天要挑战的这道题,表面是数字组合游戏,实则暗藏回溯算法的精髓。据说90%的面试者都会忽视关键细节,让我们用5分钟彻底攻克LeetCode 39题「组合总和」!

🛒 一个真实的生活场景#

小明在超市凑满减活动,手握100元优惠券发愁:

  • “巧克力20元,薯片15元,可乐5元…”
  • “同一商品可以拿多件”
  • “怎样才能刚好凑满100元的所有组合?”

这场景竟与算法题完美对应!让我们揭开题目的真面目。

问题描述#

题目目标#

给定一个无重复元素的整数数组 candidates 和一个目标整数 target ,找出 candidates 中所有和为 target 的不同组合。数组中的同一个数字可以被无限次选取,但解集不能包含重复组合。

示例 1#

输入: candidates = [2,3,6,7], target = 7 输出: [[2,2,3],[7]] 说明: 把输入和输出放在一起看,会更容易直接抓住题目要求的变化。

💡 算法题解析#

题目要求:
给定无重复元素的数组和一个目标数,找出所有唯一组合,满足:

  • 组合中数字和等于目标
  • 同一数字可无限次使用
  • 解集不能有重复组合(如[2,2,3]和[3,2,2]视为同一组合)

示例:
输入:candidates = [2,3,5], target = 8
输出:[[2,2,2,2],[2,3,3],[3,5]]

😱 新手易踩的三个坑#

  1. 暴力枚举:直接遍历所有子集,产生大量重复组合(时间复杂度O(2^n))
  2. 遗漏剪枝:不排序直接处理,无法提前终止无效搜索
  3. 路径回溯:忘记移除已添加元素,导致结果串扰

就像在超市盲目拿商品,既浪费时间又容易拿错!

🚀 高手的解题秘籍#

核心思路:回溯算法 + 剪枝优化#

算法图解#

  1. 排序数组:[2,3,5] → [2,3,5](为剪枝铺垫)
  2. 构建决策树:每个节点代表选择某个元素
  3. 剪枝策略:当累计值超过target时停止向下搜索
  4. 路径记录:用List保存当前选择路径

就像在超市:

  • 先按价格排序商品(排序)
  • 从便宜的开始拿(剪枝)
  • 记录已选商品(路径)
  • 凑满金额立即结算(终止条件)

🏆 复杂度优化关键#

  1. 排序剪枝:时间复杂度从O(2^n)降到O(n^(target/min))
  2. 避免重复:通过start参数控制选择范围,保证组合唯一性
  3. 空间优化:复用path列表,空间复杂度O(target/min)

💼 面试灵魂三问#

  1. 为什么需要排序?

    • 实现剪枝优化,提前终止无效搜索路径
    • 保证组合元素的递增顺序,避免重复组合
  2. 如何处理元素重复使用?

    • 递归时传递start=i而非i+1,允许重复选择当前元素
  3. 算法适用哪些变种题?

    • 组合总和II(不可重复使用元素)
    • 电话号码字母组合
    • 全排列问题

📌 核心技巧总结#

掌握回溯三板斧:

  1. 选择:记录当前决策
  2. 约束:通过剪枝减少搜索
  3. 撤销:回溯到上一步状态