递归
递归是指一种函数调用自身的操作。递归被用于处理包含有更小的子问题的一类问题。一个递归函数可以接受两个输入参数:一个最终状态(终止递归)或一个递归状态(继续递归)。
做递归问题最重要的是要找到出口,也就是终止递归的条件,从这个点出发,就能够反推出怎么解决。
下面用两个例子来说明:
第一个是比较经典的斐波那契数列:兔子问题:
有一对兔子,从出生后第3个月起每个月都生一对兔子,
小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问某个月的兔子总数为多少?
下面手动分析一下每个月兔子的数量:
n 兔子数
1 1
2 1
3 生一对:2对 1
4 生一对:3对 2 1
5 生两对:5对 3 2 1 1
6 生三队:8对 3 2 2 1 1 1
7 生五队:13对 3 3 2 2 2
8 生八队:21对
得出,每月的兔子数量为: 1 1 2 3 5 8 13 21 这也就是斐波拉契数列。
可以看出,当n<=2时,兔子数量为1对,>2时,每月的数量等于前面两个月数量的和,即:
当 n=1、2 1
n>2 fn = (n-1)+(n-2);
function fn(n) {
// 递归的出口 n=1 || n=2
if (n <= 2) {
return 1;
} else {
return fn(n - 1) + fn(n - 2);
}
}
// console.log(fn(8));
另外,还有一个例子。
/* 14、猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个,
第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃前一天剩下的一半零一个。
到第5天早上想再吃时,见只剩下一个桃子了。求第一天共摘多少个桃子?
继续手动分析桃子的数量:
第几天 剩余桃子数量
5 1
4 n/2 - 1 = m => n = (1+1)*2 =4
3 n/2 - 1 = ((m+1)*2+1)*2 =10
2 n/2 - 1 = (((m+1)*2+1)*2+1)*2 = 22
1 n/2 - 1 = ((((m+1)*2+1)*2+1)*2+1)*2 46
*/
可以看出,第n月的桃子数量,等于第n+1月桃子数量加1*2,即:
function monkey(n) {
// 递归的出口
if (n == 5) {
return 1;
} else {
return (monkey(++n) + 1) * 2;
}
}
// console.log(monkey(1));