319 lines
7.0 KiB
Markdown
319 lines
7.0 KiB
Markdown
# 递归
|
||
## 简答题
|
||
1. 九九乘法表
|
||
```
|
||
function num(nums){
|
||
if(nums==1){
|
||
console.log("1x1=1")
|
||
}else{
|
||
num(nums-1)
|
||
for(var i=1,str='';i<=nums;i++){
|
||
str += `${i}x${nums}=`+i*nums+' '
|
||
}
|
||
console.log(str)
|
||
}
|
||
}
|
||
num(9)
|
||
// 循环
|
||
for(var i=1;i<10;i++){
|
||
let str = ''
|
||
for(var j=1;j<10;j++){
|
||
if(i>=j){
|
||
str += `${j}x${i}=`+i*j+' '
|
||
}
|
||
}
|
||
console.log(str)
|
||
}
|
||
```
|
||
|
||
|
||
2. 定义一个函数 实现n的阶乘
|
||
```
|
||
function jc(n){
|
||
if(n<=1){
|
||
return 1;
|
||
}else{
|
||
return n*arguments.callee(n+1);
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
|
||
3. 一只青蛙可以一次跳 1 级台阶或者一次跳 2 级台阶,例如:
|
||
跳上第 1 级台阶只有一种跳法:直接跳 1 级即可。 跳上第 2 级台阶有两种跳法:每次跳 1 级,跳
|
||
两次;或者一次跳 2 级。 问要跳上第 n 级台阶有多少种跳法?
|
||
```
|
||
|
||
function ge(n){
|
||
if(n==0){
|
||
return 0;
|
||
}else if(n==1){
|
||
return 1;
|
||
}else if(n==2){
|
||
return 2;
|
||
}
|
||
return ge(n-1)+ge(n-2);
|
||
}
|
||
|
||
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
4. 编写一个函数,输入n为偶数时,调用函数求1/2+1/4+…+1/n,当输入n为奇数时,调用函数求/1+1/3+…+1/n;
|
||
```
|
||
function num(nums){
|
||
if(nums==1){
|
||
console.log("1x1=1")
|
||
}else{
|
||
num(nums-1)
|
||
for(var i=1,str='';i<=nums;i++){
|
||
str += `${i}x${nums}=`+i*nums+' '
|
||
}
|
||
console.log(str)
|
||
}
|
||
}
|
||
num(9)
|
||
// 循环
|
||
for(var i=1;i<10;i++){
|
||
let str = ''
|
||
for(var j=1;j<10;j++){
|
||
if(i>=j){
|
||
str += `${j}x${i}=`+i*j+' '
|
||
}
|
||
}
|
||
console.log(str)
|
||
}
|
||
|
||
|
||
```
|
||
|
||
|
||
|
||
|
||
5. 1+2+3+4+....+100(n)求和
|
||
```
|
||
function dg(x){ //第一题
|
||
if(x==1)return 1;
|
||
return dg(x-1)+x;
|
||
}
|
||
var lj=dg(100);
|
||
console.log(lj)
|
||
|
||
```
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
6. 细胞分裂 有一个细胞 每一个小时分裂一次,一次分裂一个子细胞,第三个小时后会死亡。那么n个小时候有多少细胞?
|
||
|
||
```
|
||
// 每三个小时为一个周期 , 第四个小时就 go die 了。
|
||
// 方法一
|
||
// 第一个小时,只有a态细胞;第二个小时,a态细胞分裂,原来的a态细胞变成了b态细胞,分裂出来的细胞变成了新的a态细胞;第三个小时,a态细胞继续分裂变成b态细胞和新的a态细胞,b态细胞分裂变成c态细胞和a态细胞;第四个小时,a、b、c态细胞都会分裂,并且按照之前的规律转变。得出下面的结论
|
||
// a 初始态 一个小时 前一个小时的 a+b+c
|
||
// b 幼年态 两个小时 前一个小时的 a
|
||
// c 成熟态 三个小时 前一个小时的 b
|
||
function allCell(n){
|
||
// a态细胞
|
||
let aCell = function(n){
|
||
if(n==1){
|
||
return 1;
|
||
}else{
|
||
return aCell(n-1)+bCell(n-1)+cCell(n-1);
|
||
}
|
||
}
|
||
// b态细胞
|
||
let bCell = function(n){
|
||
if(n==1){
|
||
return 0;
|
||
}else{
|
||
return aCell(n-1);
|
||
}
|
||
}
|
||
// c态细胞
|
||
let cCell = function(n){
|
||
if(n==1||n==2){
|
||
return 0;
|
||
}else{
|
||
return bCell(n-1);
|
||
}
|
||
}
|
||
return aCell(n)+bCell(n)+cCell(n)
|
||
}
|
||
console.log(allCell(10))
|
||
// 方法二
|
||
// 这个方法就是分成了 活着的 和 死亡的
|
||
function cell(hour){
|
||
// 活着的细胞
|
||
function livecell(hour){
|
||
if(hour<4){
|
||
// 前三个小时没有死亡的细胞 成2的n-1次方增长
|
||
return Math.pow(2,hour-1)
|
||
}else{
|
||
// 从第四个小时开始有死亡的细胞
|
||
// 活着的细胞 = 前一个小时活着的细胞 - 这个小时死去的细胞
|
||
return livecell(hour-1)*2 - diecell(hour)
|
||
}
|
||
}
|
||
// 死亡的细胞
|
||
function diecell(hour){
|
||
if(hour<4){
|
||
// 前三个小时没有死亡的细胞
|
||
return 0
|
||
}else{
|
||
// 因为三个小时一个周期
|
||
// 也就是每三个小时,(n-3)时的细胞就会死完
|
||
// 那么 这个小时(n)死去的细胞 + 上个小时(n-1)死去的细胞 + 前两个小时(n-2)死去的细胞 = 前三个小时(n-3)活着的细胞
|
||
return livecell(hour-3) - diecell(hour-1) - diecell(hour-2)
|
||
}
|
||
}
|
||
return livecell(hour)
|
||
}
|
||
console.log(cell(10))
|
||
|
||
|
||
```
|
||
|
||
|
||
|
||
7. 有 64 个格子,第一个格子放一粒麦子,第二个放2粒,第三个放4粒...每个格子都是前边的两倍。一共有多少粒?
|
||
|
||
```
|
||
let sum = 0
|
||
let start = 1;
|
||
let end = 0;
|
||
function tow(){
|
||
if(end>=64){
|
||
return false
|
||
}
|
||
sum+=start
|
||
start*=2
|
||
end++
|
||
tow()
|
||
}
|
||
tow()
|
||
console.log(sum)
|
||
|
||
```
|
||
|
||
|
||
|
||
8. 输出斐波那契数列
|
||
```
|
||
// 递归
|
||
let a = 0;
|
||
function tu(num){
|
||
a++
|
||
if(num==1||num==2){
|
||
return 1
|
||
}
|
||
let nums = tu(num-1)+tu(num-2)
|
||
return nums
|
||
}
|
||
console.log(tu(8),a)
|
||
// 闭包解决
|
||
// 也就是存在数组中,再次循环时,如果数组中已经存在,就返回数组中的值,大大减少了递归调用函数的次数
|
||
var count2=0;
|
||
var fiba = (function(){
|
||
var arr = [0,1,1]; //第0位只是占位,从第一位开始算起
|
||
return function(n){
|
||
count2++;
|
||
var res=arr[n];
|
||
if(res){// 如果arr中存在,返回这个值
|
||
console.log(res,'----')
|
||
return res;
|
||
}else{
|
||
console.log(arr[n],'+++++')
|
||
arr[n]=fiba(n-1)+fiba(n-2);
|
||
return arr[n];
|
||
}
|
||
}
|
||
})();
|
||
console.log(fiba(8),count2)
|
||
// 普通
|
||
// 普通循环解决这个问题是性能最好的。
|
||
let a = 1;
|
||
let b = 1
|
||
let c;
|
||
function tu(num){
|
||
for(let i=0;i<num-2;i++){
|
||
c = a+b;
|
||
a = b;
|
||
b = c
|
||
}
|
||
return c;
|
||
}
|
||
console.log(tu(8))
|
||
|
||
```
|
||
|
||
|
||
|
||
9.
|
||
10. 下面代码导致的问题如何解决
|
||
```
|
||
function factorial(num){
|
||
if (num <= 1){
|
||
return 1;
|
||
} else {
|
||
return num * factorial(num-1);
|
||
}
|
||
}
|
||
var anotherFactorial = factorial;
|
||
factorial = null;
|
||
alert(anotherFactorial(4));
|
||
|
||
```
|
||
答案
|
||
我们知道,arguments.callee 是一个指向正在执行的函数的指针,因此可以用它来实现对函数
|
||
的递归调用,例如:
|
||
```
|
||
function factorial(num){
|
||
if (num <= 1){
|
||
return 1;
|
||
} else {
|
||
return num * arguments.callee(num-1);
|
||
}
|
||
}
|
||
|
||
```
|
||
|
||
|
||
|
||
|
||
11. 猴子吃桃问题:猴子第一天摘下若干个桃子, 当即吃了一半,还不过瘾,又多吃了一个; 第二天早上又将剩下的桃子吃掉一半,又多吃了一个。
|
||
* 以后每天早上都吃了前一天剩下的一半零一个。 到第10天早上想再吃时,见只剩下一个桃子了。 求第一天共摘了多少。
|
||
|
||
|
||
程序分析:采取逆向思维的方法,从后往前推断。
|
||
|
||
// 倒数第1 2 3 4 5 6 天
|
||
// 桃数量1 4 10 22 46 94
|
||
// 采用递归的方法
|
||
|
||
|
||
|
||
```
|
||
// 返回第n天的桃子数量
|
||
function getValue(n){
|
||
if (n == 1) {
|
||
return 1;
|
||
}
|
||
return (getValue(n - 1) + 1) * 2;
|
||
}
|
||
|
||
for (int i = 1; i < 11; i++) {
|
||
console.log("第" + i + "天\t" + getValue(i) + "颗");
|
||
}
|
||
|
||
|
||
``` |