题目如下:
一个小孩练习爬台阶,一共10级台阶,小孩可以一次向上选择爬1 - 3级。但是第3级和第6级台阶被施加了魔法,小孩一旦踏上就会停下来就开始跳《新宝岛》。那么,不让小孩跳《新宝岛》的爬法一共有多少种?
emm,很是B站up主的风格。
解题
先看代码
#include <stdio.h>
#include <stdlib.h>
void ret(int *x, int step)
{
//第一个参数为成功的记录数,第二个参数为当前处于第几阶阶梯。
if (step == 10)
{
//到达第十阶记录加一,然后结束递归。
(*x)++;
return;
}
if (step == 3 || step == 6)
{
//如果跳珍宝岛就什么都不执行,然后结束递归。
return;
}
else if (step < 10)
{
// 条件允许继续往上走。先递归一次走一阶的。如果返回就递归走两阶的。然后第三阶。
ret(x, step + 1);
ret(x, step + 2);
ret(x, step + 3);
}
else
{
//其他情况就直接返回.
return;
}
}
int main()
{
int *n = NULL;
//用来存放已经成功的次数。用指针,传递比较方便。
int x = 0;
//成功的次数。指针指向的数。
n = &x;
ret(n, 0);
printf("%d", x);
}
最后输出 42
然后再说递归。
第一次接触时是大一的斐波那契数列。不过当时看着就头大,也不怎么理解。但是看到这道题想了一会这算法就跳出来了。
递归算法,我的理解就是分层解决问题。尤其是这种,一步一步往下深入,并且每一步往下分叉情况一样或非常类似的情况。
比如这道题。当准备迈出第一步时有三种情况,一步、两步、三步(先不考虑被禁止的),然后第二次迈时,也同样是三种情况。所以,递归的情况就有三种,而这里每次的三种情况都要递归。随意函数里是依次进行的。
然后说下原理:
假设第一条路已执行至第十阶。步程为:1 1 2 1 2 1 1 1。
但是递归的第一种可能性应该是:1 1 1 1 1 1 1 1 1 1。
然后不管这些,我们先从头看,
第一步,1
step为1
,继续深入,此时,step加一,x是指针,所以直接往下传。对于此时函数体内的一切内容,系统是保存在栈中的。
第二步,1
step为2
,再深入,同上。
第三步,1
step为3
,此时ret函数内判断不成立,然后返回。
这时,在栈中第二步的数据被唤醒,替换第三步的数据。即开始执行第二步中的
ret(x,step+2)
,此时,step为2
…
后续类似。
说明
第一、递归必须有满足条件结束的语句。
第二、递归的次数不能太多,否则容易造成栈溢出(程序会被终止)。
第三、递归相对于其他算法可大大提升效率。如果能用,就用递归。