题目
给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
示例
输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。
解析
如果是一个集合来求组合的话,就需要startIndex;如果是多个集合取组合,各个集合之间相互不影响,那么就不用startIndex;
不加剪枝的解法:
func combinationSum(candidates []int, target int) [][]int {
var path []int
var res [][]int
backtracking(0, 0, target, candidates, path, &res)
return res
}
func backtracking(startIndex, sum, target int, candidates, path []int, res *[][]int) {
if sum == target {
tmp := make([]int, len(path))
copy(tmp, path)
*res = append(*res, tmp)
return
}
if sum > target { // 这里必须有,不然出错
return
}
for i := startIndex; i < len(candidates); i++ {
path = append(path, candidates[i])
sum += candidates[i]
backtracking(i, sum, target, candidates, path, res) // 可以取多次,所以就不要i+1了
path = path[:len(path)-1]
sum -= candidates[i]
}
}
加剪枝的解法:
func combinationSum(candidates []int, target int) [][]int {
var path []int
var res [][]int
sort.Ints(candidates) //需要先排序
backtracking(0, 0, target, candidates, path, &res)
return res
}
func backtracking(startIndex, sum, target int, candidates, path []int, res *[][]int) {
if sum == target {
tmp := make([]int, len(path))
copy(tmp, path)
*res = append(*res, tmp)
return
}
if sum > target {
return
}
for i := startIndex; i < len(candidates) && sum + candidates[i] <= target; i++ { //加了剪枝,超过目标值就不用再循环了
path = append(path, candidates[i])
sum += candidates[i]
backtracking(i, sum, target, candidates, path, res)// 这里都是取得i,不像之前的是i+1,因为可以重复取
path = path[:len(path)-1]
sum -= candidates[i]
}
}
注意这道题的剪枝是需要整个先排序才能用