刷题使我快乐,满脸开心.jpg
- 来源:力扣(LeetCode)
- 链接:https://leetcode.cn/problems/combination-sum-ii/
- 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目
给定一个候选人编号的集合 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
思路
题意理解
这道题最大的难点就在这俩句话:
candidates
中的每个数字在每个组合中只能使用一次
。
也就是说,每个数字
(而不是每种数字)都可以且仅可以使用一次,因为candidates
没有说明不包含重复数字。这一点在示例中也得到了体现
- 注意:解集不能包含重复的组合。
虽然独立的数字可以自由组合,但是存在相同的数字时,得到的结果
很可能是相同
的。我们需要避免这种情况
解题思路
总体就是回溯
的思路,关键在于重复数字
的选择问题上了,我的方法如下:
- 先排序,简化操作
- 在排序的前提下,转换一个概念,重复数字并非不能选,而是要在每个遍历层级上不能选择重复的。
进入下一个遍历层级时,就可以选择相同数字了。排序的情况下,相当于结果集中的每个顺位上,不能再选择一样的数字了。
思路还是挺简单的,细节在注释~
代码
func combinationSum2(candidates []int, target int) [][]int {
// 先排序,便于去重处理
sort.Ints(candidates)
n := len(candidates)
results := make([][]int, 0)
var find func(result []int, restTarget, index int)
find = func(result []int, restTarget, index int) {
// 不符合的选择,或者已经没得数字可选了,直接返回
if restTarget < 0 || index > n {
return
}
// 符合要求的记录结果
if restTarget == 0 {
// result 传递的是指针,隔绝此机制影响
temp := make([]int, 0)
temp = append(temp, result...)
results = append(results, temp)
}
// 尝试遍历
for i := index; i < n; i++ {
// i > index 有两个作用,
// 一是 防止 candidates[i-1] 越界
// 二是 同一层级不再选择相同数字(并非不能选相同数字,而是在不同层级去选)
if i > index && candidates[i] == candidates[i-1] {
continue
}
// 选择数字去尝试
result = append(result, candidates[i])
find(result, restTarget-candidates[i], i+1)
// 回溯
result = result[:len(result)-1]
}
}
find(make([]int, 0), target, 0)
return results
}
作者:LittleStone
链接:https://leetcode.cn/problems/combination-sum-ii/solutions/2657620/shu-ju-biao-xian-yi-ban-dan-shi-gan-jue-9zpff/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。