这样说明的话可能有点抽象,那么我们来换个方法说明。
当你发现,你的问题需要用到多重循环,具体几重循环你又没办法确定,那么就可以使用我们的回溯算法来将循环一层一层的进行嵌套。
就像这样:
void f(int depth) { if (depth == max) { return; } for (...) { f(depth + 1); } }这样套起来的话,无论多少重循环我们都可以满足。
关键词:深度优先遍历、迷宫
回溯四步走由于上述网上的步骤太抽象了,所以在这里我自己总结了回溯四步走:
由于回溯法一般采用递归方法实现,所以大家可以结合【算法】递归三步走来进行理解。
编写检测函数(非必须)编写检测函数:检测函数用来检测此路径是否满足题目条件,是否能通过。
这步不做硬性要求。。不一定需要
1. 明确函数功能1.明确函数功能:要清楚你写这个函数是想要做什么?它的参数是什么?它的全局变量是什么?
递归的时候要按照题目的要求来设置函数功能,再根据函数功能来设置函数的参数。
其实我们按照题目要求来设置函数功能,最后总是莫名其妙就把问题给解决了,可能很多人都觉得这也太奇妙了吧。
理解:其实递归的理论基础其实就是制定查找规则,按照这个规则找答案,一定能找到答案。
例如,这个题:面试题 04.06. 后继者,做出来之后觉得莫名其妙就找到答案了。
问题:可是如果完全按照题目要求来设置函数功能的话,那根据先序遍历和中序遍历来确定后序遍历函数的方法参数真的能返回一个数组吗?
技巧:
全局变量和方法参数:(当前节点状态)这个方法的参数最好由递归时的当前阶段的状态决定!最好这个方法的参数能够记录我们当前阶段(当前节点)的状态!
注意:我们的递归方法的方法参数,都是为了表明我们所绘树形图的当前节点的状态。
当然,不仅仅是递归方法的方法参数,也包括全局成员变量也可以表示当前节点状态。
(这个当前阶段的状态一般指递归深度depth,而不是第几个分支i,分支选择是由 for (int i = 0; i < length; i++) 中的 i 来决定的,不需要我们写入函数参数中。(只是有时候depth和i恰好相等而已)
比如,如果我们这个方法需要实现阶乘,那么我们的方法参数需要记录当前阶乘的数字(即 当前阶段的状态)
返回数据:返回数据应该是我们遇到递归出口之后,需要告诉给前一步递归的信息数据!
比如,计算阶乘我们就需要在遇到递归出口之后,告诉我们前一步递归我们现在的结果数据,方便整合。
特别注意:递归函数的返回值最好设置为单个元素,比如说一个节点或者一个数值,告诉前一步递归我们现在的结果数据即可。
如果返回值是数组的话,我们将无法从中提取到任何有效信息来进行操作;
如果结果需要数组的话,我们可以将数组作为公共变量返回值为void,我们在方法体里面操作数组即可。
注意:因为回溯法我们一般只关心叶子结点的结果,中间的过程函数一般没什么返回的作用,所以函数返回值类型一般为void或者boolean,boolean可以为函数返回查找结果。
当然,也不排除中间节点返回的结果有作用的情况。不过这种情况也可以用递归函数的方法参数来存放以及利用所有返回的结果。
操作:方法参数 depth,递归出口if (depth >= n)