C语言解决青蛙跳台阶问题(升级版)

目录
  • 1. 基础问题
    • 题目描述
    • 解题思路
    • 代码实现
  • 2. 问题升级
    • 题目描述
    • 解题思路
    • 代码实现
  • 3. 特性总结

1. 基础问题

题目描述

一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

诺,就像下面这样

解题思路

其实我一看到这道题,我也是懵的,不知道从哪里着手分析,那我们就从最简单的情况开始分析。

假如 n = 1,一共有一级台阶,显然就只有一种跳法

一次跳1阶;

假如 n = 2,一共有两级台阶,共有两种跳法

跳1阶,再跳1阶

跳2阶

假设n = 3,共有三种跳法。

跳1阶,跳1阶,再跳1阶

跳1阶,再跳2阶

跳2阶, 再跳1阶

(注:此过程图是我从网上找的,实在是难得画啦)

通过上面的分析,我们可以这样思考问题

前往楼梯顶部的最后一步,要么跳1阶,要么跳2阶;

先假设f(n)为 n 级台阶的总跳法数;

那么第一次如果选择跳一级的话,剩下的 n-1 级台阶的跳法数就为f(n−1)。

如果第一次跳两级的话,剩下的 n-2 级台阶的跳法就是f(n−2);

现在青蛙一次只能跳一级或两级,所以我们可以推出以下公式:

咦,这玩意儿不就是我们 斐波那契数 吗?

只不过有一点不同的是,斐波那契数列一般是以1,1,2,3,5,8,13……开始的;

而我们这是以1,2,3,5,8,13……开始的,少了最前面的一个1。

代码实现

上面说到这个过程有点类似于斐波那契数,但又不完全是,所以我们先看主代码部分

#include <stdio.h>
int jump(int n)
{
    if (n < 3)
    {
        //假设n的范围是[0, 3]
        return n;
    }
    else
    {
        //n>3的时候
        return jump(n - 1) + jump(n - 2);
    }
}

int main()
{
    int num = 0;
    printf("请输入一个台阶数:> ");
    scanf("%d", &num);

    int ret = jump(num);

    printf("小青蛙有 %d种 跳法\n", ret);
    return 0;
}

运行结果

但是,我们来看一下计算的过程

要计算f(6),就需要先计算出子问题f(5)和f(4)

然后要计算f(5),又要先算出子问题f(4)和f(3),以此类推。

一直到f(2)和f(1),递归树才终止。

因此,青蛙跳阶,递归解法的时间复杂度 等于O(1) * O(2ⁿ)=O(2ⁿ)

你仔细观察这颗递归树,你会发现存在「大量重复计算」;

比如f(4)被计算了两次,f(3)被重复计算了3次…所以这个递归算法低效的原因,就是存在大量的重复计算!

所以我们可以对代码进行优化

递归升级

在递归法的基础上,新建一个长度为n的数组,用于在递归时存储f(0)至f(n) 的数字值,重复遇到某数字时则直接从数组取用,避免了重复的递归计算。

所以我们设置一个数组,用于存放第一次计算某一个n的jump(n)。

当每一次要计算一个jump(n)的时候,就先查看数组中以n为下标的地方是否有值,有的话就可以不调用jump(n),而直接从数组中取得结果值,否则再计算jump(n)。

代码实现

#include <stdio.h>

long int f[1000]={0};
int jump(int n){
    //当只有一阶台阶的时候,只有一种上台阶的方式。

    //当有2阶台阶的时候,有2种上台阶的方式,一种是一次上一阶,还有一种是一次上2个台阶。

    //现在设有n阶台阶,如果n>2,那种应该有(先跳一阶)+(先跳2阶)的方式

    //如果先跳一阶,那么就有jump(n-1)中方式。如果先跳2阶,那么就有jump(n-2)中方式。

    //因此可以知道共有jump(n-1) + jump(n-2)种方式。
    if(n==1)
    {
        f[1]=1;
        return f[1];
    }

    if(n==0)
    {
        f[0]=1;
        return f[0];
    }

    if(n==2)
    {
        f[2]=2;
        return f[2];
    }
    else
    {
        if(f[n-1]!=0)
        {
            if(f[n-2]!=0)
            {
                return (f[n-1]+f[n-2]);
            }
            else
            {
                f[n-2]=jump(n-2);
                return (f[n-1]+f[n-2]);
            }
        }
        else
        {
            if(f[n-2]!=0)
            {
                f[n-1]=jump(n-1);
                return (f[n-1]+f[n-2]);
            }
            else
            {
                f[n-1]=jump(n-1);
                f[n-2]=jump(n-2);
                return (f[n-1]+f[n-2]);
            }
        }
    }
}

int main()
{
    int num = 0;
    printf("请输入一个台阶数:> ");
    scanf("%d", &num);

    int ret = jump(num);

    printf("小青蛙有 %d种 跳法\n", ret);
    return 0;
}

运行结果

动态规划解法

很快我又发现,不必把所有的记录都记起来;

假设我有3阶楼梯,我只需要知道跳2阶和跳1阶的方法数是多少就可以算出跳3阶的方法数;

因此每次只需要保留n−1阶和n−2阶的方法数。

代码实现

#include <stdio.h>

int jump(int n)
{
    //n=0、1、2的时候,直接返回n即可
    if (n < 3)
    {
        return n;
    }

    //第一个数为1
    int one = 1;

    //第二个数为2
    int two = 2;

    //用于存放前两个数之和
    int sum = 0;
    while (n > 2)
    {
        sum = one + two;
        one = two;
        two = sum;

        n--;
    }
    return sum;
}

int main()
{
    int num = 0;
    printf("请输入一个台阶数:> ");
    scanf("%d", &num);

    int ret = jump(num);

    printf("小青蛙有 %d种 跳法\n", ret);
    return 0;
}

运行结果

2. 问题升级

题目描述

一只青蛙一次可以跳上一级台阶,也可以跳上二级台阶……,也可以跳n级,求该青蛙跳上一个n级的台阶总共需要多少种跳法。

解题思路

一只青蛙要想跳到n级台阶,可以从一级,二级……,也就是说可以从任何一级跳到n级

当台阶为1级时,f(1)=1;

当台阶为2级时,f(2)=1+1=2;

当台阶为3级时,f(3)=f(1)+f(2)+1=4;

当台阶为4级时,f(4)=f(1)+f(2)+f(3)+1=8;

当台阶为5级时,f(5)=f(1)+f(2)+f(3)+f(4)+1=16;

所以递推公式我们很容易就能想到:f(n)=f(n−1)+f(n−2)+……+f(2)+f(1)+f(0)

最后这个f(0)是可以去掉的,因为0级就相当于没跳,所以f(0)=0

然后我们把f(0)去掉再转换一下:f(n−1)=f(n−2)+f(n−3)+……+f(2)+f(1);

推导过程

我们列两个等式:

①f(n)=f(n−1)+f(n−2)+f(n−3)+…+f(2)+f(1)

②f(n−1)=f(n−2)+f(n−3)+…+f(2)+f(1)

由①-②得,f(n)=2f(n−1)

代码实现

递归方法

代码示例

int jump(int n)
{
    if (n == 1)
    {
        return 1;
    }
    else
    {
        return 2 * jump(n - 1);
    }
}

int main()
{
    int num = 0;
    printf("请输入一个台阶数:> ");
    scanf("%d", &num);

    int ret = jump(num);

    printf("小青蛙有 %d种 跳法\n", ret);
    return 0;
}

运行结果

非递归方法

当然这里也可以用非递归的方式来实现

那么非递归怎么去思考呢?

可以这样理解:

然后使用用函数pow(2,n -1),需要加头文件<math.h>

但是我们这里可以不用库函数来实现,给大家介绍一种神奇的运算

代码示例

int jump(int n)
{
    if (n == 1)
    {
        return 1;
    }
    else
    {
        return 1 << (n-1);
    }
}

int main()
{
    int num = 0;
    printf("请输入一个台阶数:> ");
    scanf("%d", &num);

    int ret = jump(num);

    printf("小青蛙有 %d种 跳法\n", ret);
    return 0;
}

运行结果

我这里选择用<<左移操作符来计算

3. 特性总结

其实这道算法题的本质可以说就是斐波那契数的衍生;

反言之,对于算法,我的理解:算法本质就是数学的解题过程

以上就是C语言解决青蛙跳台阶问题(升级版)的详细内容,更多关于C语言青蛙跳台阶的资料请关注我们其它相关文章!

(0)

相关推荐

  • C语言解决青蛙跳台阶问题(升级版)

    目录 1. 基础问题 题目描述 解题思路 代码实现 2. 问题升级 题目描述 解题思路 代码实现 3. 特性总结 1. 基础问题 题目描述 一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级.求该青蛙跳上一个 n 级的台阶总共有多少种跳法. 诺,就像下面这样 解题思路 其实我一看到这道题,我也是懵的,不知道从哪里着手分析,那我们就从最简单的情况开始分析. 假如 n = 1,一共有一级台阶,显然就只有一种跳法 一次跳1阶: 假如 n = 2,一共有两级台阶,共有两种跳法 跳1阶,再跳1阶 跳2阶

  • C语言 递归解决青蛙跳台阶问题

    目录 前言 一.求解思路 二.代码实现 1.参考代码 2.运行结果 总结 前言 一只青蛙一次可以跳1级或2级台阶,求当台阶数为n时青蛙有多少种跳法. 一.求解思路 台阶的数量为n. 当 n = 1 时,青蛙有一种跳法,即跳1级台阶. 当 n = 2 时,青蛙有两种跳法,即跳两次1级台阶或跳一次2级台阶. 当 n = 3 时,青蛙可以先跳2级台阶再跳1级台阶,也可以选择先跳1级台阶再跳2级台阶,或者是跳三次1级台阶.依次类推,我们就能知道台阶数为n时青蛙的跳法. 但是,这样子是不是很麻烦呢,再仔细

  • Java解决青蛙跳台阶问题流程

    1.问题描述 一只青蛙一次可以跳上1阶台阶,也可以跳上2阶台阶,求该青蛙跳上一个n阶台阶总共有多少种跳法? 2.画图分析  3.问题讲解  一只青蛙,要么1次跳2个台阶,要么1次跳1个台阶. 假设3个台阶为例:如果1次跳1个台阶,那剩下几种跳法?我们来仔细地想一下: 跳了一个台阶之后,剩下的台阶就相当于3 -1个台阶剩下2个台阶,2个台阶的跳法如上图就是2种跳法. 如果一次跳2个台阶,剩下的台阶就相当于3 - 2个台阶剩下1个台阶,1个台阶的跳法如上图是1种跳法.那么加起来就是3种跳法. 所以说

  • C 语言基础实现青蛙跳台阶和汉诺塔问题

    目录 一.青蛙跳台阶 题目 思路 分析 1. 从跳法次数分析 2. 从过程分析 二.青蛙跳台阶变式1 题目 分析 三.青蛙跳台阶变式2 题目 分析 四.汉诺塔问题(求步数) 题目 思路 分析 五.汉诺塔问题(求移动过程) 题目 思路 分析 一.青蛙跳台阶 题目 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶.求该青蛙跳上一个 n 级的台阶总共有多少种跳法 思路 遇见题目我们可以在纸上先动手画画,把最简单的几种方式列出来,作比较,找规律. 分析 按照上面表格可以从跳法次数,过程,或者两者结合找规

  • 手把手带你用java搞定青蛙跳台阶

    目录 问题描述 问题剖析 n=1 n=2 n=3 n=4 小结 Java代码示例 附:C语言实现青蛙跳台阶 总结 问题描述 一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级.求该青蛙跳上一个n 级的台阶总共有多少种跳法 问题剖析 n=1 此时有一种跳法. n=2 此时有两种跳法. n=3 此时有三种跳法. n=4 此时有五种跳法. 小结 当有n级台阶时,青蛙可以跳1级,也可以跳2级.如果它跳1级,那么还剩下n-1级台阶:如果它跳2级,那么还剩下n-2级台阶.因此n级台阶的跳法等于n-1级台阶跳

  • Java青蛙跳台阶问题的解决思路与代码

    问题描述 一只青蛙一次可以跳上1级台阶,也可以一次跳上2级台阶,请问跳上n级台阶,该请娃一共有多少种跳法? 解决思路 ①如果只有1级台阶,那显然只有一种跳法. ②如果有2级台阶,那么就有2种跳法,一种是分2次跳.每次跳1级,另一种就是一次跳2级. ③如果台阶级数大于2,设为n的话,这时我们把n级台阶时的跳法看成n的函数,记为,第一次跳的时候有2种不同的选择:一是第一次跳一级,此时跳法的数目等于后面剩下的n-1级台阶的跳法数目,即为,二是第一次跳二级,此时跳法的数目等于后面剩下的n-2级台阶的跳法

  • C语言递归之汉诺塔和青蛙跳台阶问题

    递归就是一个函数执行过程中调用自己,在c语言中有很多关于递归的经典问题,例如:斐波那契数列问题.汉诺塔问题等,在研究递归问题时我们要注意三点: 1.递归的结束条件 2.递归在每次进行过程中,都得离条件越来越近 3.相邻两次递归调用之间的关联关系 汉诺塔问题: 有三根杆子A, B, C.A杆上有N个(N > 1)穿孔圆盘, 盘的尺寸由下到上依次变小.要求按下列规则将所有圆盘移至C杆: 1.每次只能移动一个圆盘: 2.大盘不能叠在小盘上面,可将圆盘临时置于B杆, 也可将从A杆移出的圆盘重新移回A杆,

  • php中青蛙跳台阶的问题解决方法

    一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 思路: 1.找规律 f(1)=1 f(2)=2 f(3)=3 f(4)=5 f(n)=f(n-1)+f(n-2)这是一个斐波那契数列 2.因为调到第n个台阶时,倒数第一个台阶可以一步跳过来,倒数第二个台阶也可以一步就跳过来 非递归版本: JumpFloor(target) if target==1 || target==2 return target jumpSum=0 jum

  • 利用简洁的C语言代码解决跳台阶问题与约瑟夫环问题

    跳台阶问题 题目: 一个台阶总共有 n 级,如果一次可以跳 1 级,也可以跳 2 级. 求总共有多少总跳法,并分析算法的时间复杂度. 分析: 也是比较基础的题目,通过递归可以方便的求解 代码实现如下(GCC编译通过): #include "stdio.h" #include "stdlib.h" int function(int n); int main(void) { int tmp; tmp = function(5); printf("%3d\n&q

  • Python中跳台阶、变态跳台阶与矩形覆盖问题的解决方法

    前言 跳台阶.变态跳台阶.矩形覆盖其实都和斐波那契数列是一类问题,文中通过示例代码介绍的非常详细,下面话不多说了,来一起看看详细的介绍吧. 跳台阶 问题描述: 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法. 分析: 初始值很容易得到,当n > 2时,跳上n级台阶最后一步无外乎两种情况,从第n-1级跳一级跳上来,或是从第n-2级跳2级跳上来,因此很容易得到如下递归公式. F(0)= 0 F(1)= 1 F(2)= 2 F(n)= F(n-1)+ F(n-

随机推荐