回溯:
有递归就会有回溯,递归和回溯相辅相成,回溯通常藏在递归函数的下面。
回溯函数其实就是递归函数,没有单独的回溯函数
效率:
回溯函数是一个纯暴力的搜索。
有的问题用for循环一点一点搜索都搜索不出来,一定要用回溯才能搜索出来
哪些问题for循环一点一点搜索都搜索不出来,一定要用回溯才能搜索出来?
组合问题。
e.g. 1234有多少种两两组合? 12 13 14.。。。
切割问题。
e.g. 给一个字符串,有几种切割方式?
子集问题。
e.g. 1234的子集有哪些?1 2 3 4 12 13 14。。。
排列问题。
e.g. 12的排列有12和21.
棋盘问题。
e.g. N皇后、解数独
怎么理解回溯法?
把回溯法抽象为图像,做题的时候要画图。
回溯法可以抽象为N叉树,树的宽度是要处理的集合的大小,深度是递归的深度(要通过递归处理)
回溯的模板
在回溯算法中,我的习惯是函数起名字为backtracking,这个起名大家随意。
回溯算法中函数返回值一般为void。
void backtracking(参数){
//什么时候达到了终止条件,树中就可以看出,一般来说搜到叶子节点了,也就找到了满足条件的一条答案,把这个答案存放起来,并结束本层递归。
if (终止条件) {
存放结果;
return;
}
//回溯函数遍历过程伪代码如下
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
处理节点;
backtracking(路径,选择列表); // 递归,根据树,从上往下递归
回溯,撤销处理结果
}
}
//为什么要撤销处理结果?
//比如123排列组合问题
//12处理完以后,要把12撤销,组合13;13处理完以后,要把13撤销,组合23
回溯三部曲
递归函数参数返回值
确定终止条件
单层递归逻辑