算法思想
定义
回溯法(探索与回溯法)是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
适用范围
有许多问题,当需要找出它的解集(全部解)或者要求回答什么解是满足某些约束条件的最优解时,往往要使用回溯法。
- 有组织的穷举式搜索
回溯法的基本做法是搜索或者有的组织穷尽搜索。它能避免搜索所有的可能性。即避免不必要的搜索。这种方法适用于解一些组合数相当大的问题。
- 搜索解空间树
回溯法在问题的解空间树中,按深度优先策略,从根结点出发搜索解空间树。算法搜索至解空间树的任意一点时,先判断该结点是否包含问题的解。如果肯定不包含(剪枝过程),则跳过对该结点为根的子树的搜索,逐层向其祖先结点回溯;否则,进入该子树,继续按深度优先策略搜索。
为了实现回溯,我们先弄明白以下两个问题:
1)首先应该明确问题的解空间。
2)其次是组织解空间以便它能用以被搜索
回溯算法框架
解决⼀个回溯问题,实际上就是⼀个决策树的遍历过程。只需要思考 3 个问题:
- 路径:也就是已经做出的选择。
- 选择列表:也就是你当前可以做的选择。
- 结束条件:也就是到达决策树底层,⽆法再做选择的条件。
result = []
def backtrack(路径, 选择列表):
if 满⾜结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(路径, 选择列表)
撤销选择
for 选择 in 选择列表:
# 做选择
将该选择从选择列表移除
路径.add(选择)
backtrack(路径, 选择列表)
# 撤销选择
路径.remove(选择)
将该选择再加⼊选择列表
其核⼼就是 for 循环⾥⾯的递归,在递归调⽤之前「做选择」,在递归调⽤之后「撤销选择,特别简单。
写 backtrack 函数时,需要维护⾛过的「路径」和当前可以做的「选择列
表」,当触发「结束条件」时,将「路径」记⼊结果集。
递归要点
(1)递归参数
(2)终止条件
(3)递推工作
(4)返回值
其他参考
1.基本思想
2.迭代回溯的一般框架
3. 回溯法例题
【题目1】:矩阵中的路径(剑指offer-12)
【题目2:】机器人的运动范围
【题目3】:二叉树中和为某一值的路径(剑指offer-34)
【题目4】: 全排列(leetcode 46/47)
【题目5】:字符串的排列
【题目4】N皇后
给你⼀个 N×N 的棋盘,让你放置 N 个皇后,使得它们不能互相攻击。PS:皇后可以攻击同⼀⾏、同⼀列、左上左下右上右下四个⽅向的任意单位。参考解析