题目
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
- 只使用数字1到9 每个数字
- 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例
输入: k = 3, n = 7
输出: [[1,2,4]]
解释:
1 + 2 + 4 = 7
没有其他符合的组合了。
解析
这道题和上一道组合问题很接近,只不过是多了一个终止条件,直接上回溯+剪枝的代码:
func combinationSum3(k int, n int) [][]int {
//要找K个数的和为n
var res [][]int
var path []int
sum := 0
var backTrack func(int)
backTrack = func(startIndex int) {
//剪枝
if sum > n || len(path) > k {
return
}
//递归终止条件
if len(path) == k && sum == n {
tmp := make([]int, k) //一样的原因
copy(tmp, path)
res = append(res, tmp)
return
}
//单层递归循环+剪枝
for i := startIndex; i <= 9-(k-len(path))+1; i++ {
sum += i
path = append(path, i)
backTrack(i+1)
//回溯
sum -= i
path = path[:len(path)-1]
}
}
backTrack(1)
return res
}
也可以将结果定义成函数外面的全局变量,然后在外定义函数;或者传数组的地址进来:
func combinationSum3(k int, n int) [][]int {
res := [][]int{}
path := []int{}
sum := 0
if n < 0 || n < 0 {
return res
}
backTrackint(n, k, sum, 1, &path, &res)
return res
}
func backTrackint(n, k, sum, startIndex int, path *[]int, res *[][]int) {
if sum > n || len(*path) > k { // 第一个剪枝
return
}
if sum == n && len(*path) == k {
temp := make([]int, k)
copy(temp, *path)
*res = append(*res, temp)
return
}
for i := startIndex; i <= 9-(k-len(*path))+1; i++ {
*path = append(*path, i)
sum += i
backTrackint(n, k, sum, i+1, path, res) // 第二个错误,这里不能带星号,因为要递归调用这个函数
sum -= i
*path = (*path)[:len(*path)-1] // 第一个错误,这里需要用*path类型
}
}
全局变量的:
var res [][]int
var path []int
var sum int
func combinationSum3(k int, n int) [][]int {
res = [][]int{}
if n < 0 || k < 0 {
return res
}
brackTracing(n, k, 1, sum)
return res
}
func brackTracing(n, k, startIndex, sum int) {
if sum > n || len(path) > k { // 这个也算剪枝
return
}
if sum == n && len(path) == k{
temp := make([]int, k)
copy(temp, path)
res = append(res, temp)
}
for i := startIndex; i <= 9 - (k - len(path)) + 1; i++ { //注意这里是9,因为是从1-9中取,不剪枝的话直接就是i <= 9
path = append(path, i)
sum += i
brackTracing(n, k, i+1, sum)
path = path[:len(path)-1]
sum -= i
}
}