递归算法一直就是个很难理解的问题,这个问题确实是非常的复杂,就算是计算机,以他的运行速度去解决递归问题也会是非常的难。
递归就是函数本身调用本身,说白了就是已知前一项的结果就能够很直接的得到当前项的结果。所以递归可以解决所有的数列问题。所以递推也可以用递归来解决。但是不推荐使用递归。因为递归的执行速率太低。但是当我们遇到了一些问题没有办法去描述,用递归的办法就可能会很容易的解决了这个问题。
比如汉诺塔问题:
如何去描述这个规律呢,如何将n个盘子通过中间柱移到目标柱。
这个问题没有办法去描述,但是可以将汉诺塔问题抽象为,首先将n-1个盘子通过目标柱移到中间柱,然后将第n个盘子移到目标柱,最后再将n-1个盘子移到目标柱。这样我们就解决了这个问题。当只有一个盘子的时候我们是知道怎么移动的。
js解决递归问题:
var n = Number(prompt("请输入盘子的个数"));
var step = 0;
move(n);
alert(n+"次可以将盘子移动到目标柱");
function move(n){
if(1 == n){
step ++;
return ;
}else{
move(n-1);
step ++;
move(n-1);
}
}
再举个例子:
上台阶的问题:已知上台阶可以一步上一个台阶也可以一步上两个台阶。问n个台阶有多少种上法。
这个问题也是好像没有什么好的方式去描述。但其实已知
当只有1个台阶只有1种上法,只有2个台阶有2种上法
假设这个人就迈一步,这一步有两种可能就是一步上一个台阶和一步上两个台阶
那么这个问题就可以直接写为:
var n = Number(prompt("请输入台阶的个数"));
var sum = go(n);
alert("总共有"+sum+"种上台阶的方法");
function go(n){
if(n==1 || n==2){
return n;
}else{
go(n-1) + go(n-2);
}
}
总结:对于递归问题
首先要确定已知的值
在汉诺塔中已知的值就是:当只有一个盘子的时候就只有一个走法。
然后就是找到n和n-1的关系(就是降阶)将复杂的问题简单化。
在汉诺塔中:假设知道了n-1种走法,接下来就是把最大的盘子移到目标柱然后再把n-1个盘子移到目标柱。
再举个例子:猴子选大王问题,一圈猴子,选大王报数,报的数为3就自动退出,直到最后一只猴子当选为猴王。
这个问题怎么描述:
假设只有一个猴子的时候就是0号猴子当选了。
当我们知道n-1个猴子的是如何选猴王的时候,我们很容易的就知道了n个猴子是谁当选了。这个时候可以去试试,举例当有3个猴子谁当选,加进来1只猴子之后谁当选。其实关系就是当前的猴子+3后面的那只猴子当选。
js实现代码为
function selectKing(n){
if(1 == n){
return 0;
}else{
(selectKing(n-1)+3)%n;
}
}
var n = Number(prompt("请输入一个数"));
var king = selectKing(n);
alert(king+1+"号猴子当选");
其实汉诺塔问题也是一个数列
盘子的个数 | 移动的次数 |
---|---|
1 | 1 |
2 | 3 |
3 | 7 |
其实移动的次数也就是2的n次方-1
那台阶的问题:
台阶的个数 | 移动的方法 |
---|---|
1 | 1 |
2 | 2 |
3 | 3 |
4 | 5 |
台阶移动方法的个数就是数列的前两项的和
猴子选大王的问题
猴子的个数 | 大王的编号 |
---|---|
1 | 0 |
2 | 1 |
3 | 1 |
4 | 0 |
猴子大王就是前一项的大王编号+3对猴子的个数取余的结果
其实递归就是解决某种有数列的简单的方式,但是他的计算得速率比较慢,但是从大局的角度去理解,递归是非常简单的方式。只要对函数有深刻的理解。就能很好的利用递归。都是理论上说函数调用函数的效率比较低。但是 我并没有去测验,之后有时间我会去再做一个测验看看两者的效率到底有什么区别,如果区别不大,也可以使用递归去解决。表面上看,我输入一个汉诺塔的次数为200会运行好一会但是如果使用公式计算2的200次方 很快就计算出来了。所以递归的效率应该还是比较低的。所以尽量的少使用递归!