关于青蛙跳台阶问题的讨论

本文探讨了青蛙跳台阶问题与斐波那契数列的关系,通过递归方法实现并分析了其效率问题,随后提出从前往后计算的优化策略,以提高代码执行速度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、引言

首先青蛙跳台阶的问题就是:1只青蛙可以一次跳1个或者跳2个台阶,那么请问它跳n个台阶有几种跳法?

这个问题,我们可以先尝试列举1,2,3,4,5...个台阶来看看有什么规律。表格如下:

台阶123456789
跳法1235813213455

我们不难发现,跳法这一行的数字是斐波那契数列的一个变化

*ps:什么是斐波那契数列:后一个数字是前两个数字的和,第1和第二个数字都是1。那就是:

1,1,2,3,5,8,13,21,34,55...

递推公式为:     f(n)\left\{\begin{matrix}1 & n=1,2\\ f(n-1)+f(n-2) & n>3 \end{matrix}\right.


二、斐波那契数列

斐波那契数列是个非常典型的递归问题。我们可以尝试用递归来写代码,代码如下:

#include <stdio.h>

int fib(int x)
{
    int c = 1;
    if (x>2)
    {
        c = fib(x-1)+fib(x-2);
    }
    return c;
}

int main()
{
    int n = 0;//告诉我们要知道第几项斐波那契数
    printf("请输入项数:");
    scanf ("%d",&n);
    int ret = fib(n);//设置fib这个函数来求斐波那契数
    printf ("第%d项斐波那契数是:%d",n,ret);//打印最终的结果
    return 0;
}

但是当我们输入50甚至更大的数字之后会发现运算极其的缓慢 ,这是为什么呢?

我们可以尝试写出如下代码,来看看我们计算的时候 f(3) 被运算了多少次。

#include <stdio.h>

int count = 0;//创造一个全局变量来把算了多少次f(3)记录下来。

int fib(int x)
{
    int c = 1;
    if (x==3)
    {
        count++;
    }
    if (x>2)
    {
        c = fib(x-1)+fib(x-2);
    }
    return c;
}

int main()
{
    int n = 0;//告诉我们要知道第几项斐波那契数
    printf("请输入项数:");
    scanf ("%d",&n);
    int ret = fib(n);//设置fib这个函数来求斐波那契数
    printf ("第%d项斐波那契数是:%d\n",n,ret);//打印最终的结果
    printf("%d",count);//打印count
    return 0;
}

 我们可以尝试跑一下代码,当n=40的时候,我们会惊奇的发现 f(3) 被算了39088169次,从而导致了我们的计算速度是如此的缓慢。

那我们可以如何优化代码使我们的运算效率便达呢?

我们可以这样想,既然递归是从后往前算,我们何不如转换思路,从前往后算呢。

实际上我们可以把相邻的三个数字看成a,b,c.

先将a+b的值赋给c,然后将b的值赋给a,c的值赋给b,再将n-1。这样我们就完成了一次循环。之后的斐波那契数列何尝不是这样计算。我们给出下图,方便于理解。

 那我们就可以用如下代码尝试优化:

#include <stdio.h>

int fib(int x)
{
    int a = 1;
    int b = 1;
    int c = 1;
    while (x>2)
    {
        c = a + b;//后一项为前两项的和
        a = b;//重新赋值
        b = c;
        x--;
    }
    return c;
}

int main()
{
    int n = 0;//告诉我们要知道第几项斐波那契数
    printf("请输入项数:");
    scanf ("%d",&n);
    int ret = fib(n);//设置fib这个函数来求斐波那契数
    printf ("第%d项斐波那契数是:%d",n,ret);//打印最终的结果
    return 0;
}

这样就解决了计算效率的问题。


三、青蛙跳台阶问题的解法

讲完了斐波那契数列的写法,轻而易举的我们就可以稍加改动来完成青蛙跳台阶的问题。

#include <stdio.h>

int fib(int x)
{
    int a = 1;
    int b = 2;    
    int c = 3;  //这里的c可以改为任何数,这里为了方便读者理解,就取了第三项的值  
    while (x>2)
    {
        c = a + b;//后一项为前两项的和
        a = b;//重新赋值
        b = c;
        x--;
    }
    return c;
}

int main()
{
    int n = 0;   //初始化n来放置台阶数
    printf("请输入台阶数:");
    scanf ("%d",&n);
    if (n>2)
    {
        int ret = fib(n);
        printf("青蛙跳的方式有%d次",ret);
    }
    switch(n)
    {
        case 2:
            printf("青蛙跳的方式有%d次",n);
            break;
        case 1:
            printf("青蛙跳的方式有%d次",n);
            break;
    }
    return 0;
}

由于前两个数字不一样我们并不能在fib函数中返回c,但是我们可以让n=1和2的时候不进入fib函数直接输出结果就行了。

四、总结

青蛙跳台阶的问题本质上就是斐波那契数列的问题,下次我们可以回归本质来看问题。

有的问题适合递归,有的并不适合,我们可以多多尝试,从而优化代码与计算量。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值