解决一个回溯问题,实际上就是一个决策树的遍历过程。
- 路径:也就是已经做出的选择。
- 选择列表:也就是你当前可以做的选择。
- 结束条件:也就是到达决策树底层,无法再做选择的条件。
遍历当前可选择的项,在递归调用之前做选择,在递归调用之后撤销选择
回溯算法的框架:
result = []
def backtrack(路径, 选择列表):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
以上框架可以套到一些经典问题中:
求集合的全排列
问题:给定一个不含重复数字的整数数组 nums
,返回其 所有可能的全排列 。可以 按任意顺序 返回答案。
思路:假设集合[1,2,3], 每次可选择的列表为去掉路径中已有的元素,遍历可选择的choose列表,选择一条路(即一个整数),递归,结束条件是choose列表为空,回溯(撤销这次选择,继续遍历...
func permute(nums []int) [][]int {
if len(nums) == 0{
return [][]int{}
}
var res [][]int
var backtrack func([]int,[]int)
backtrack = func(path []int,choose []int) {
if len(choose) == 0{
res = append(res,path)
}
for index, c := range choose{
leftChoose := []int{}
leftChoose = append(leftChoose,choose[:index]...)
leftChoose = append(leftChoose,choose[index+1:]...)
//新的choose列表 排除当前元素,
backtrack(append(path,c),leftChoose)
}
}
backtrack([]int{},nums)
return res
}
求集合的所有子集
问题:给定一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。解集 不能 包含重复的子集。
输入:nums = [1,2,3] 输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
思路:由于不能包含重复的子集,每次选择之后,新的choose列表是当前path之后的所有元素,即path=[1,],可选择的只有[2,3]; 如果path=[2,],可选择的只有[3,];每次都将path加入到结果中,及时path=[],空集也是其子集之一;
func subsets(nums []int) [][]int {
if len(nums) == 0{
return [][]int{[]int{}}
}
var res = [][]int{}
var backtrack func([]int,[]int)
backtrack = func(path []int,choose []int) {
res =append(res,path)
for index,c := range choose{
addChoose := []int{}
addChoose = append(addChoose,choose[index+1:]...)
// 新的choose列表是当前path之后的所有元素
tmp := append([]int{},path...)
tmp = append(tmp,c)
backtrack(tmp,addChoose)
}
}
backtrack([]int{},nums)
return res
}
求括号的组合方式
问题:正整数 n 代表生成括号的对数,请设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
思路:这道题的每次的选择有两种,左括号或者右括号,在选择时要注意 右括号的数量不能大于左括号的数量 ()))这种path是不允许的;结束条件是括号都匹配完毕
func generateParenthesis(n int) []string {
if n <= 0{
return []string{}
}
var res []string
var backtrack func(string,int,int)
backtrack = func(path string, left, right int) {
if left == 0 && right == 0{
res = append(res, path)
}
if left > 0{
backtrack(path+"(",left-1,right)
}
if left < right{
backtrack(path+")",left,right-1)
}
}
backtrack("",n,n)
return res
}
01背包问题
问题描述:给你一个背包, 最多可以承受的重量为w,那么给你一组物品,每个物品无法分割,问在背包总重量和总物品数量不超过约定数量的前提下,如何做才能够让背包的总重量最重。
func bagWeight(item []int,weight int)int{
if len(item) == 0 || weight <= 0{
return 0
}
var maxWeight = 0
var backtrack func(choose [] int, curWeight int)
backtrack = func(choose [] int, curWeight int){
if curWeight > weight{
return
}
if curWeight > maxWeight{
maxWeight = curWeight
}
for index, c := range choose{
leftChoose := append([]int{},choose[index+1:]...)
backtrack(leftChoose,curWeight+c)
}
}
backtrack(item,0)
return maxWeight
}