题目描述
给定一个候选人编号的集合 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用 一次 。
注意:解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]
提示:
- 1 <= candidates.length <= 100
- 1 <= candidates[i] <= 50
- 1 <= target <= 30
解题思路
基本想法还是回溯算法。可以通过递归的方式来尝试每一个数字,看看能否找到满足条件的组合。
1 | func combinationSum2(candidates []int, target int) [][]int { |
上面的代码是没办法通过的,因为它没有处理重复的组合。而如果要在递归过程中跳过重复的数字,那就需要对 candidates
进行排序,并在递归中添加判断来跳过重复的数字。
这里又由于数据范围的限制 1 <= candidates[i] <= 50
和 1 <= target <= 30
,所以可以参照桶排序的思路来优化。
1 | func combinationSum2(candidates []int, target int) [][]int { |
上面的代码是通过数组 candidatesCnt
的下标来表示数字,数组的值表示该数字在 candidates
中出现的次数。如果数字超过 30,则不考虑它,因为 target
的最大值为 30。
而如果数据范围很大,不适用桶排法的话,就可以考虑使用二维数组来存储每个数字的出现次数。
1 | func combinationSum2(candidates []int, target int) [][]int { |
总结
本题主要考察回溯算法的应用。通过对候选数组的排序和去重处理,可以有效地避免重复组合的产生。在实现过程中,使用了递归函数来尝试每一种可能的组合,并在找到满足条件的组合时将其记录下来。