时间复杂度:O(nlog n)
解题思路
回溯法,对每一个数字都有两种选择——放入和不放入。递归边界为target≤0即数组中的总和不小于target。
先对candidates数组由小到大排序,然后回溯法搜索每一种情况,尝试放入candidates数组每一个元素,但可以通过事先剪枝不放入那些如果放入数组后总和超过target的元素来提高效率。
AC代码
自己实现
func combinationSum(candidates []int, target int) [][]int {
res:=[][]int{}
var dfs func(int,int)
nums:=[]int{}
dfs=func (sum,start int){
if sum>=target{
if sum==target{
res=append(res,append([]int{},nums...))
}
return
}
for i:=start;i<len(candidates);i++{
nums=append(nums,candidates[i])
dfs(sum+candidates[i],i)
nums=nums[:len(nums)-1]
}
}
dfs(0,0)
return res
}
参考解法
func combinationSum(candidates []int, target int) [][]int {
temp,res:=[]int{},[][]int{}
sort.Ints(candidates)
dfs(candidates,target,0,temp,&res)
return res
}
func dfs(nums []int,target int,index int,temp []int,res *[][]int){
//递归边界
if target<0{
return
}
//找到一个答案
if target==0{
t:=make([]int,len(temp))
copy(t,temp)
*res=append(*res,t)
return
}
//尝试放入每个元素
for i:=index;i<len(nums);i++{
//剪枝
if nums[i]>target{
break
}
temp=append(temp,nums[i])//放入该元素
dfs(nums,target-nums[i],i,temp,res)//注意下一次递归还是从当前的i开始,因为可以重复放入
temp=temp[:len(temp)-1]//回溯消除影响
}
}
感悟
看到这种寻找所有可行解的题一定要想到回溯法,递归搜索每种情况,搭配剪枝可以极大提升效率。