一、基本思想
回溯法(Backtracking)是一种通过尝试所有可能的解决方案
来求解问题的方法。它通常适用于在给定约束条件
下搜索问题的所有解,或者找到满足特定条件
的一个解。
二、适用场景
回溯法适用于以下情况:
- 组合问题:需要找出满足特定条件的组合。
- 排列问题:需要找出满足特定条件的排列。
- 图问题:需要找出满足特定条件的路径或遍历。
- 棋盘问题:需要找出满足特定条件的棋盘布局或解决方案。
三、求解步骤
回溯法的求解步骤如下:
1. 选择路径:在每一步选择中,根据问题的限制条件和约束条件,选择一个合适的路径。
2. 探索路径:根据选择的路径,继续向下探索,进入下一步。
3. 撤销选择:当发现当前路径不满足条件时,需要回退到上一步,撤销选择,选择其他路径。
4. 终止条件:当达到终止条件时,找到一个解,或者已经搜索完所有可能的路径。
注📢:回溯算法的常用手段是DFS深度优先算法+剪枝,而DFS算法一般用递归或栈方法实现。
四、算法案例
题目:剑指Offer 12 矩阵中的路径
给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
例如,在下面的 3×4 的矩阵中包含单词 “ABCCED”(单词中的字母已标出)。
输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true
利用回溯法求解:
func exist(board [][]byte, word string) bool {
// 避免取值出错
if len(board) == 0 || len(board[0]) == 0 {
return false
}
var dfs func(i, j, k int) bool
dfs = func(i, j, k int) bool {
if i < 0 || i >= len(board) || j < 0 || j >= len(board[0]) || board[i][j] != word[k] {
return false
}
if k == len(word)-1 {
return true
}
// 先临时修改该位置的值,避免搜索下一个值时造成影响
board[i][j] = ' '
// 按照下、右、左、上顺序搜索下一值
ans := dfs(i+1, j, k+1) || dfs(i, j+1, k+1) || dfs(i, j-1, k+1) || dfs(i-1, j, k+1)
// 值复原
board[i][j] = word[k]
return ans
}
for i, arr := range board {
for j, _ := range arr {
fmt.Println("i:", i, ", j:", j)
if dfs(i, j, 0) {
return true
}
}
}
return false
}