一、什么是回溯算法?
1:回溯法也可以叫做回溯搜索法,它是一种搜索的方式。
2:回溯是递归的副产品,只要有递归就必会有回溯(一一对应,一次递归必对应一次回溯)。基于这一点,可以认为,回溯函数也就是递归函数,指的都是同一个函数。
二、回溯法解决(面向)的问题有哪些?
回溯法,一般可以解决如下几种(5种)问题:
- 组合问题:N个数里面按一定规则找出k个数的集合(无顺序之分 [1 2] == [2 1])
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式(有顺序之分 [1 2] != [2 1])
- 棋盘问题:N皇后,解数独等
三、如何理解回溯算法?
这里引用carl哥教我们的方式,把回溯过程理解为一个N叉树。
注:
for循环do的是横向遍历(N叉树的宽度就是for循环的循环次数,也即待遍历的集合元素个数)
递归do的是纵向遍历(N叉树的深度就是递归的最大的递归层数)
四、回溯算法类型题目的解题步骤
Step 1:识别是否这套题属于以上的5种问题,是,就马上想到得弄回溯算法来do!
Step 2:默写回溯法模板!
//默写回溯算法模板
void backTracking(Params){
if(回溯/递归函数终止条件){
//保存结果;
return;//返回上一轮递归
}
for(遍历整个集合的elems){
//处理节点
backTracking(Params);//递归
//回溯操作
}
}
注:
第1点--- 回溯/递归函数的终止条件,必须要想清楚想完整(根据题目具体的要求)
第2点--- 确定整个集合(一般是数组):应该是从哪儿到哪儿,比如,[1 ~ 9]
第3点--- 处理节点:这里其实才是这道题目你真正完全要自己考虑并写出来的代码(如何处理具体每个节点的代码。)
无论do什么题目,识别出来是上述的几大问题,就要用回溯法来do,同时也要先默写出回溯法的模板!然后再处理具体节点代码!然后这道题就AC了!
Step 3:填写模板内容,以及写代码处理题目对应的logic。