跳到正文
第 39 题中等

组合总和

Combination Sum

从候选数组中选出和等于 target 的组合,同一个数可以重复使用;不能有重复组合。

在力扣中练习

题目描述

给你一个 无重复元素 的整数数组 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
输出: []

 

提示:

  • 1 <= candidates.length <= 30
  • 2 <= candidates[i] <= 40
  • candidates 的所有元素 互不相同
  • 1 <= target <= 40

解题思路

主解法

回溯 · 排序 + 剪枝

从 start 往后选,允许重复选当前数,超过剩余就停

组合不关心顺序,[2,5] 和 [5,2] 是同一个组合。用 start 保证下一层只从当前下标往后选,就不会产生顺序不同的重复。

同一个数可以重复使用,所以递归时传 i 而不是 i+1;只有换下一个数时才让下标前进。

分步图解

候选已排序;同一元素可以重复选,所以递归仍从 i 开始,而不是 i+1。

已排序候选 · 灰色下标不能再选
0
1
2
3
2
5
6
9
剩余 11
remain=11res=0
path
空
1 / 4
候选排序后从 2 开始尝试:装不下的候选直接 break,一路剪枝凑出第一组 [2, 2, 2, 5]。

先排序,循环中一旦 candidates[i] > remain 就 break:后面的候选只会更大,继续试没有意义。这个剪枝能省掉大量废枝。

分步图解

候选 6 大于剩余 5,后面只会更大,直接 break。

已排序候选 · 灰色下标不能再选
0
1
2
3
2
5
6
9
i
剩余 5
remain=5res=1
path
2
2
2
1 / 4
6 放不进剩余 1,直接 break;随后回退,换 9 得到 2+9。

自拟候选 [2,5,6,9]、target 11 有三个解:2+2+2+5、2+9、5+6。注意 6 在剩余 1 时必须立即停止,而不是继续尝试 9。

时间 O(指数级,受剪枝影响)空间 O(target / minCandidate)

易错点

  • 递归传 i+1:同一个数不能重复使用,会漏掉 2+2+2+5。
  • 递归传 0:会产生 [2,5] 与 [5,2] 等重复组合。
  • 不排序也不 break:结果正确但会多做大量无效递归。
  • remain < 0 才停止:多走一层废枝,还可能把负数候选也带进来。

代码与演示

演示输入candidates = [2,5,6,9],target = 11

候选已排序;同一元素可以重复选,所以递归仍从 i 开始,而不是 i+1。

已排序候选 · 灰色下标不能再选
0
1
2
3
2
5
6
9
剩余 11
remain=11res=0
path
空
1 / 5
查看 C++ 代码

延伸阅读

  • “可以重复选”与“不能重复组合”并不矛盾:前者靠传 i,后者靠 start 只往后看。
  • 如果候选含重复数字且每个只能用一次,需要先排序并在同一层跳过相同值。