递归的三种使用方向:
1.用递归完成递推问题
2.模拟连续发生的动作
3.进行"自动"的分析
1.用递归完成递推问题
1.将我们的关注点放到要求解的目标上(如斐波那契数)。
2.第n-1次和第n次之间有无关联。(f(n) = f(n-1)+f(n-2))
如:求阶乘(第n项的阶乘解为:第n-1项的阶乘解*n)、数组求和(前n位的和是前n-1位的和+arr[n])。
3.一定要确定递归的出口
一般是考虑当n==1或者n==0时。
2.用递归来模拟连续发生的动作
1.搞清楚连续发生的动作是什么(如汉诺塔的移动)。
汉诺塔:是将n块铁饼由原始柱子(称之为A)经过中专柱子(称之为B),移动到目标柱子(称之为C)上。
第一步:将前n-1块铁饼移动到B柱子上,
第二步:将第n块铁饼移动到C柱子上,
第三步:将B柱子上的n-1块柱子,通过A柱子移动到C柱子上(一个新的汉诺塔移动问题,n-1块铁饼,原始柱子为B,中转柱子为A,目标柱子为C)
2.搞清楚不同次的动作之间的区别(即是每次递归调用时,哪一个是原始柱子,哪一个是目标柱子,哪一个是中转柱子)。
3.递归的出口条件(当只有一个铁饼时,如何解决问题)
3.进行"自动"的分析问题
1.自动分析的核心一定要改变你的思想。首先你要相信你的递归函数能够解决问题。
2.再根据这个递归函数将问题代入,思考如何使用递归函数。
3.递归的出口条件。
最简单的情况下的问题是如何被解决的。
“自动分析问题”案例:
放苹果的方法:若有m个苹果,n个盘子。请问针对m,n一共有多少种方法。(顺序不影响,1,2和2,1属于同种方法)
首先假定我们可以通过函数int count(m,n);解决这个问题
那么,分析两种可能出现的情况:
1.苹果的数量>=盘子的数量(m >= n)
2.苹果的数量<盘子的数量(m < n)
if(m<n)
因为苹果的数量小于盘子的数量,无论如何选择,至少会有一个盘子为空,那么我们将这个盘子移除也不会影响方法的数量。所以count(m,n)=count(m,m);//如果选择空出更多的盘子则由第二种情况判定方法数量。
if(m>=n)
那么,可能有两种不同的情况,你可以选择每个盘子都至少放一个苹果,也可以选择空一定数量的盘子(空盘子的数目至少为1)。
1.有空盘子
count(m,n)= count (m,n-1);//去掉多余的盘子
2. 没有空盘子
没有空盘子时,则至少每一个盘子都会有一个苹果,那么我们先将每一个盘子中的苹果都删除,也不会影响放苹果的方法会重复。再将空的盘子都一处
所以count(m,n)=count(m-n,n);现在苹果的数量<盘子的数量了。
综上:
写出以下count函数:
int count (m,n)
{
//递归出口
if(m<=1||n<=1) //当只有一个苹果或只有一个盘子时,只有一种方法
return 1;
//苹果数小于盘子数
if(m<n)
return count(m,m);
//苹果数大于等于盘子数
else
{
//没有空盘子的方法 + 空盘子的方法
return count(m-n,n)+count(m,n-1);
}
}