前言
今天带大家进行新的篇章了回溯法,回溯法其实在二叉树中也经常会有使用到的地方,其实有递归就会有回溯,但回溯到底是什么呢?一文带大家弄懂。本文用于记录自己的学习过程,同时向大家进行分享相关的内容。本文内容参考于代码随想录同时包含了自己的许多学习思考过程,如果有错误的地方欢迎批评指正!
回溯法理论基础
什么是回溯
其实回溯法也可以叫做回溯搜索法,是一种搜索的方式,其实我们在二叉树种也经常用到回溯,提到回溯的概念。回溯其实跟递归是同时存在的,有回溯就会有递归。
回溯法并不是什么高效的算法,并且相对来说回溯法是比较难以理解的。因为我们回溯的本质是在做一个穷举,列举出所有的可能从而找到我们需要的结果。当然有些可以稍微高效点,比如剪枝,什么意思就如果要找个路径当出现一个不符合的时候,其后面所有的可能也不需要了,因为有这个不符合的存在,这条路径是肯定不符合我们需要的路径的。
回溯法解决的问题
为什么回溯法并不是那么高效,我们还要用还要学回溯法呢,是因为其所解决的问题都是很难的问题,没有别的很好的方法来求解的问题。一般解决下列问题:
- 组合问题:N个数里面按一定规则找出k个数的集合
- 切割问题:一个字符串按一定规则有几种切割方式
- 子集问题:一个N个数的集合里有多少符合条件的子集
- 排列问题:N个数按一定规则全排列,有几种排列方式
- 棋盘问题:N皇后,解数独等等
每个都不简单,具体实战后续会有所讲解的,现在就是带大家知道下可以解决这些问题,还有个需要注意的就是,组合和排列的区别,就是组合是不区分顺序的,但是排列就是区分顺序的,对于(1,2)和(2,1),这是同一个组合,却不是同一个排列。
怎么做回溯
既然回溯跟递归是相辅相成的,那么做递归时的递归三部曲,这里回溯同样有着回溯三部曲
- 回溯函数模板返回值以及参数:回溯函数的返回值一般是没有的,并且其所需要的具体参数其实也不是说可以一下子就确定下来的,我们需要去根据具体的题目,看我们会使用需要哪些参数在去写。
- 回溯函数终止条件:就像在树中一样,当找到了叶子节点的时候就返回即可
- 回溯搜索的遍历过程:回溯的遍历过程其实就是跟递归差不多,我觉得回溯最重要的体现在哪里,就是我们在递归前处理了当前节点,然后进入递归,递归结束处理后在撤销我们对当前节点的处理,这就是回溯思想的非常重要的体现。
写回溯的模板就是下面的,后面会在题目中实战中有所涉及哦。
def backtracking(参数):
if (终止条件):
存放结果
return
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)):
处理节点
backtracking(路径,选择列表)// 递归
回溯,撤销处理结果