回溯算法介绍
回溯算法通常用于解决组合、切割、子集、排列等问题。本文将为你提供一个回溯算法的基本框架,它可以被用来解决这些类型的问题。该框架遵循三个主要步骤:选择、探索和撤销选择。
模板如下:
package main
import "fmt"
// 回溯函数的基本框架
func backtrack(path []int, selections []int, results *[][]int) {
// 如果满足结束条件,将结果保存起来
if isSolution(path) {
solution := make([]int, len(path))
copy(solution, path)
*results = append(*results, solution)
return
}
// 遍历所有选择
for _, selection := range selections {
// 做出选择
path = append(path, selection)
// 排除不合法的选择
if !isValid(path) {
path = path[:len(path)-1] // 撤销选择
continue
}
// 进入下一层决策树
backtrack(path, selections, results)
// 撤销选择
path = path[:len(path)-1]
}
}
// isSolution 判断当前路径是否为解决方案
func isSolution(path []int) bool {
// 根据具体问题实现结束条件
// 例如:达到路径的特定长度,或满足特定的条件
return false // 示例中默认返回false
}
// isValid 判断当前路径是否为有效选择
func isValid(path []int) bool {
// 根据具体问题实现有效性检查
// 例如:检查是否有重复元素,或者路径是否满足特定约束
return true // 示例中默认返回true
}
func main() {
// 初始化路径和结果容器
var path []int
var results [][]int
// 初始化选择列表
selections := []int{1, 2, 3} // 示例中的选择列表
// 执行回溯
backtrack(path, selections, &results)
// 打印结果
fmt.Println("所有可能的解决方案:", results)
}
本文中将带大家在不同场景下运用这个模板去解出不同的leetcode题目
leetcode 46 全排列
给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入: nums = [1,2,3]
输出: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入: nums = [0,1]
输出: [[0,1],[1,0]]
示例 3:
输入: nums = [1]
输出: [[1]]
func permute(nums []int) [][]int {
results:= make([][]int,0)
backtrack([]int{},nums,len(nums),&results)
return results
}
func backtrack(path []int,selections []int,maxLen int,results*[][]int) {
if len(path) == maxLen {
res := make([]int,len(path))
copy(res,path)
*results = append(*results,res)
return
}
for idx,selection := range selections {
path = append(path,selection)
newSelections := make([]int,len(selections))
copy(newSelections,selections)
newSelections= Remove(newSelections,idx)
backtrack(path,newSelections,maxLen,results)
path = path[:len(path)-1]
}
}
func Remove(nums []int,idx int) []int {
nums = append(nums[0:idx],nums[idx+1:]...)
return nums
}
leetcode 22 括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入: n = 3
输出: ["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入: n = 1
输出: ["()"]
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入: n = 3
输出: ["((()))","(()())","(())()","()(())","()()()"]
示例 2:
输入: n = 1
输出: ["()"]
func generateParenthesis(n int) []string {
if n == 0 {
return nil
}
res := make([]string,0)
backtrack("",n,n,&res)
return res
}
func backtrack(str string,left,right int,res*[]string) {
if left == 0 && right == 0 {
*res = append(*res,str)
return
}
if left>0 {
backtrack(str+"(",left-1,right,res)
}
if right>0 && right>left{
backtrack(str+")",left,right-1,res)
}
}
leetcode 77 组合
给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
你可以按 任何顺序 返回答案。
示例 1:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
示例 2:
输入: n = 1, k = 1
输出: [[1]]
func combine(n int, k int) [][]int {
if n < k {
return nil
}
results := make([][]int,0)
backtrack([]int{},n,k,1,&results)
return results
}
func backtrack(combination []int,n,k,idx int,results*[][]int) {
if len(combination) == k {
res:= make([]int,k)
copy(res,combination)
*results = append(*results,res)
}
for i := idx;i <= n;i++ {
combination = append(combination,i)
backtrack(combination,n,k,i+1,results)
combination = combination[:len(combination)-1]
}
}