【Golang必备算法】回溯算法

77. 组合

注意:使用切片表达式的得到的切片和原来的切片共用同一个底层数组

剪枝操作:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uvNUUAKq-1640443748589)(https://gitee.com/CJ-cooper6/picgo/raw/master/image-20211130172501586(1)].png)

代码

var res [][]int
var ans []int
func combine(n int, k int) [][]int {
res=[][]int{}
ans=[]int{}
backtrack(n,k,1)

return res
}

func backtrack(n,k,index int){

if len(ans)==k{
    a:=make([]int,len(ans))	//这里要创建新的切片,不然后面对修改ans会改变res的,因为共用一个底层数组
    copy(a,ans)
    res=append(res,a)
    return 
}
for i:=index;i<=n-(k-len(ans))+1;i++{//剪枝操作,如果没有足够的元素不进行下一步
    ans=append(ans,i)
    backtrack(n,k,i+1)
    ans=ans[0:len(ans)-1]
}

}


216. 组合总和 III
var result [][]int
var ans []int
var sum int
func combinationSum3(k int, n int) [][]int {
    result=[][]int{}
    ans=[]int{}
    sum=0

    backstrack(k,n,sum,1)

    return result
}

func backstrack(k,n,sum,index int){
    if sum > n{
        return
    }
    if len(ans)==k{
        if sum == n{
            t:=make([]int,k)
            copy(t,ans)
            result=append(result,t)
            return
        }
    }

    for i:=index;i<=9-(k-len(ans))+1;i++{
        ans=append(ans,i)
        sum+=i
        backstrack(k,n,sum,i+1)
        sum-=i
        ans=ans[:len(ans)-1]
    }

}

17. 电话号码的字母组合

本题和之前题不同,这道题是多个集合求组合,而之前的是一个集合求组合

var m map[byte][]byte
var res []string
var ans []byte
func letterCombinations(digits string) []string {
    if len(digits)>4 || len(digits)==0{
        return []string{}
    }
    m=map[byte][]byte{
    '0':{},
    '1':{},
    '2':{'a','b','c'},
    '3':{'d','e','f'},
    '4':{'g','h','i'},
    '5':{'j','k','l'},
    '6':{'m','n','o'},
    '7':{'p','q','r','s'},
    '8':{'t','u','v'},
    '9':{'w','x','y','z'},
}
    res=[]string{}
    ans=[]byte{}
    str:=[]byte(digits)
    backtrack(len(str),str,0)

    return res

}

func backtrack(n int,arr []byte,outindex int){

    if len(ans)==n{
        t:=string(ans)
        res=append(res,t)
        return 
    }

    letter:=m[arr[outindex]]    // 取数字对应的字符集

    for i:=0;i<len(letter);i++{
        ans=append(ans,letter[i])
        backtrack(n,arr,outindex+1)
        ans=ans[:len(ans)-1]    //回溯
    }


}

39. 组合总和
var res [][]int
var ans []int
func combinationSum(candidates []int, target int) [][]int {
    res=[][]int{}
    ans=[]int{}
    sort.Ints(candidates)

    backstrack(candidates,target,0,0)

return res
}

func backstrack(candidates []int,target int,sum int,index int){
    if sum > target{
        return
    }
     if sum == target{
         t:=make([]int,len(ans))
         copy(t,ans)
         res=append(res,t)
         return 
        }

    for i:=index;i<len(candidates);i++{
        sum+=candidates[i]
        ans=append(ans,candidates[i])
        backstrack(candidates,target,sum,i)
        sum-=ans[len(ans)-1]
       ans=ans[:len(ans)-1]
    }
}

40. 组合总和 II

这道题关键是元素在同一个组合内是可以重复的,怎么重复都没事,但两个组合不能相同。

所以引入ued数组

代码

var res [][]int
var ans []int
var used []bool
func combinationSum2(candidates []int, target int) [][]int {
    res = [][]int{}
    ans = []int{}
    used = make([]bool,len(candidates))
    sort.Ints(candidates)
    backstrack(candidates,target,0,0,used)
    return res
}

func backstrack(candidates []int,target int,sum int,index int,used []bool){
    if sum == target{
        t:=make([]int,len(ans))
        copy(t,ans)
        res=append(res,t)
        return 
}  

    for i:=index;i<len(candidates) && sum+candidates[i] <= target;i++{
           // used[i - 1] == true,说明同一树支candidates[i - 1]使用过
           // used[i - 1] == false,说明同一树层candidates[i - 1]使用过
           // 要对同一树层使用过的元素进行跳过
        if i>0 && candidates[i]==candidates[i-1] && used[i-1]==false{
            continue
        }
        sum+=candidates[i]
        ans=append(ans,candidates[i])
        used[i]=true
        backstrack(candidates,target,sum,i+1,used)
        used[i]=false
        sum-=ans[len(ans)-1]
        ans=ans[:len(ans)-1]
    }
}

78. 子集
var res [][]int
var ans []int
func subsets(nums []int) [][]int {
 res=[][]int{}
 ans=[]int{}
backstrack(nums,0)
return res
}

func backstrack(nums []int,index int){
    t:=make([]int,len(ans))
    copy(t,ans)
    res=append(res,t)   
    for i:=index;i<len(nums);i++{
        ans=append(ans,nums[i])
        backstrack(nums,i+1)
        ans=ans[:len(ans)-1]
    }    
    
}

46. 全排列
var res [][]int 
var ans []int
func permute(nums []int) [][]int {
    res = [][]int{}
    ans = []int{}
    used := make([]bool,len(nums))
    backstrack(nums,used)

    return res

}

func backstrack(nums []int,used []bool){
    if len(ans) == len(nums){
        t:=make([]int,len(ans))
        copy(t,ans)
        res=append(res,t)
        return 
    }
    for i:=0;i<len(nums);i++{
        if used[i]==false{
            ans=append(ans,nums[i])
            used[i]=true
        }else{
            continue
        }

        backstrack(nums,used)
        used[i]=false
        ans=ans[:len(ans)-1]
    }
}

47. 全排列 II
var res [][]int 
var ans []int
func permuteUnique(nums []int) [][]int {

   res = [][]int{}
    ans = []int{}
    used := make([]bool,len(nums))

    sort.Ints(nums)
    backstrack(nums,used)

    return res
}


func backstrack(nums []int,used []bool){
    if len(ans) == len(nums){
        t:=make([]int,len(ans))
        copy(t,ans)
        res=append(res,t)
        return 
    }
    for i:=0;i<len(nums);i++{
        if i>0 && nums[i]==nums[i-1] && used[i-1]==false{
            continue
        }
        if used[i]==false{
            ans=append(ans,nums[i])
            used[i]=true
        }else{
            continue
        }

        backstrack(nums,used)
        used[i]=false
        ans=ans[:len(ans)-1]
    }
}
    if i>0 && nums[i]==nums[i-1] && used[i-1]==false{
        continue
    }
    if used[i]==false{
        ans=append(ans,nums[i])
        used[i]=true
    }else{
        continue
    }

    backstrack(nums,used)
    used[i]=false
    ans=ans[:len(ans)-1]
}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值