递归与回溯

前言

之前在做的几道题Combination Sum、Generate Parentheses、Permutations,涉及到了递归和回溯的问题。

当时觉得这是一回事儿,都是自己调用自己,没太注意。后来仔细想了一下,二者并不是完全一样。

查找了相关资料之后,明白了二者的区别和联系,特此写篇博客进行记录。

递归

为了描述问题的某一个状态,必须用到该状态的上一个状态,而描述上一状态,又必须用到上一状态的上一状态,以此类推。

这种自己来定义自己的方法,称为递归定义

  • 例子:
    举个例子,递归方法好比是一队人走到了一个迷宫中,到达了第一个分岔路口,其中有三条通道。总队长命令三个小队分别探测三条通道,三个小队沿着各自通道继续前进,一直到达了每条路的下一个分叉口。
    在各个分叉口也是同样,每个小队的小队长再分别派人探路(假设人手是足够的——即计算机内存是足够的)。
    这样,最后一定会有人找到到出口,于是这个人只需要层层上报队长,最后上报到总队长,就可以得到这样的一条通路(可行解)了。

回溯

从问题的某一种可能出发,探索从这种情况出发所能达到的所有可能。当这一条路走到“尽头”时,再倒回出发点,从另一个可能触发,继续探索。

这种不断进行“回溯”寻找可行解的方法,称为回溯法

  • 例子:
    回溯法就像是一个人在走迷宫的思维模拟,每次模拟到死路时,只能退回来寻找一条新的可行路径。

区别与联系

  • 递归是一种算法结构。

递归算法会依赖前一步的结果,它的结果来源于一条主线,是确定的,而不是试探的结果。
递归会出现在子程序中自己调用自己或者间接自己调用自己。比如,斐波那契数列的计算:

long Fibonacci(unsigned int n)
{
     if(n == 0)
         return 0;
     else if(n == 1)
       	return 1;
     else
         return Fibonacci(n-1) + Fibonacci(n-2);
}
  • 回溯是一种算法思想,可以用递归实现。

简单的说,回溯就是一种试探,类似于穷举法。该方法放弃关于问题规模大小的限制,并将问题的方案某种顺序逐一枚举和试验。
发现当前方案不可能有解时,就选择下一个方案,倘若当前方案不满足问题的要求时,继续扩大当前方案的规模,并继续试探。
如果当前方案满足所有要求时,该方案就是问题的一个解。放弃当前方案,寻找下一介方案的过程称为回溯。

同时,回溯有减枝的功能。
比如在我们上一道算法题Combination Sum中,有:

//target>=candidates[i]是一种减枝的功能
for(int i = begin;i<candidates.size() && target>=candidates[i];i++){
	tmpRes.push_back(candidates[i]);;
	backTracking(candidates, target-candidates[i], res, tmpRes, i);
	tmpRes.pop_back();  //恢复
}

这是一种搜索过程的优化。

总的来说,回溯算法和递归算法不能以类别的形式进行比较。在很多情况下,二者是一起使用的。

参考文章:
[1] 回溯与递归算法的区别
[2] 回溯和递归区别

你可能感兴趣的:(Self-Culture,Algorithm)