回溯法可以叫做回溯搜索法,是一种搜索法式,有递归就会有回溯。
回溯函数也就是递归函数,指的都是一个函数。
效率并不高,因为是穷举,最多剪枝一下,可以理解成暴力搜索
组合问题:N个数⾥⾯按⼀定规则找出k个数的集合(不强调顺序,{1,2}、{2,1}这是相同的)
切割问题:⼀个字符串按⼀定规则有⼏种切割⽅式
⼦集问题:⼀个N个数的集合⾥有多少符合条件的⼦集
排列问题:N个数按⼀定规则全排列,有⼏种排列⽅式(强调顺序,{1,2}、{2,1}这是不同的)
棋盘问题:N皇后,解数独等
回溯法解决的问题都可以抽象为树形结构,因为回溯法解决的都是在集合中递归查找⼦集,集合的⼤⼩就构成了树的宽度,递归的深度,都构成的 树的深度。 递归就要有终⽌条件,所以必然是⼀颗⾼度有限的树(N叉树)。
回溯算法中函数返回值⼀般为void。再来看⼀下参数,因为回溯算法需要的参数可不像⼆叉树递归的时候那么容易⼀次性确定下来,所以⼀ 般是先写逻辑,然后需要什么参数,就填什么参数
void backtracking(参数)
回溯函数终⽌条件:
什么时候达到了终⽌条件,树中就可以看出,⼀般来说搜到叶⼦节点了,也就找到了满⾜条件的⼀条答 案,把这个答案存放起来,并结束本层递归
if(终止条件) {
存放结果;
return;
}
回溯函数遍历过程伪代码如下:
for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩)) {
处理节点;
backtracking(路径,选择列表); //递归
回溯,撤销结果
}
for循环就是遍历集合区间,可以理解⼀个节点有多少个孩⼦,这个for循环就执⾏多少次。 backtracking这⾥⾃⼰调⽤⾃⼰,for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这 棵树全遍历完了,⼀般来说,搜索叶⼦节点就是找的其中⼀个结果了 。
void backtracking(参数) { if (终⽌条件) { 存放结果; return; } for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩)) { 处理节点; backtracking(路径,选择列表); // 递归 回溯,撤销处理结果 } }