溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C語言如何解決青蛙跳臺階問題

發(fā)布時間:2022-03-04 10:17:54 來源:億速云 閱讀:173 作者:小新 欄目:開發(fā)技術(shù)

小編給大家分享一下C語言如何解決青蛙跳臺階問題,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

    1. 基礎(chǔ)問題

    題目描述

    一只青蛙一次可以跳上 1 級臺階,也可以跳上 2 級。求該青蛙跳上一個 n 級的臺階總共有多少種跳法。

    諾,就像下面這樣

    C語言如何解決青蛙跳臺階問題

    解題思路

    其實我一看到這道題,我也是懵的,不知道從哪里著手分析,那我們就從最簡單的情況開始分析。

    假如 n = 1,一共有一級臺階,顯然就只有一種跳法

    一次跳1階;

    C語言如何解決青蛙跳臺階問題

    假如 n = 2,一共有兩級臺階,共有兩種跳法

    跳1階,再跳1階

    C語言如何解決青蛙跳臺階問題

    跳2階

    C語言如何解決青蛙跳臺階問題

    假設(shè)n = 3,共有三種跳法。

    跳1階,跳1階,再跳1階

    C語言如何解決青蛙跳臺階問題

    跳1階,再跳2階

    C語言如何解決青蛙跳臺階問題

    跳2階, 再跳1階

    C語言如何解決青蛙跳臺階問題

    (注:此過程圖是我從網(wǎng)上找的,實在是難得畫啦)

    通過上面的分析,我們可以這樣思考問題

    前往樓梯頂部的最后一步,要么跳1階,要么跳2階;

    C語言如何解決青蛙跳臺階問題

    先假設(shè)f(n)為 n 級臺階的總跳法數(shù);

    那么第一次如果選擇跳一級的話,剩下的 n-1 級臺階的跳法數(shù)就為f(n−1)。

    如果第一次跳兩級的話,剩下的 n-2 級臺階的跳法就是f(n−2);

    現(xiàn)在青蛙一次只能跳一級或兩級,所以我們可以推出以下公式:

    C語言如何解決青蛙跳臺階問題

    咦,這玩意兒不就是我們 斐波那契數(shù) 嗎?

    只不過有一點不同的是,斐波那契數(shù)列一般是以1,1,2,3,5,8,13……開始的;

    而我們這是以1,2,3,5,8,13……開始的,少了最前面的一個1。

    代碼實現(xiàn)

    上面說到這個過程有點類似于斐波那契數(shù),但又不完全是,所以我們先看主代碼部分

    #include <stdio.h>
    int jump(int n)
    {
        if (n < 3)
        {
            //假設(shè)n的范圍是[0, 3]
            return n;
        }
        else
        {
            //n>3的時候
            return jump(n - 1) + jump(n - 2);
        }
    }
    
    int main()
    {
        int num = 0;
        printf("請輸入一個臺階數(shù):> ");
        scanf("%d", &num);
    
        int ret = jump(num);
        
        printf("小青蛙有 %d種 跳法\n", ret);
        return 0;
    }

    運行結(jié)果

    C語言如何解決青蛙跳臺階問題

    但是,我們來看一下計算的過程

    要計算f(6),就需要先計算出子問題f(5)和f(4)

    然后要計算f(5),又要先算出子問題f(4)和f(3),以此類推。

    一直到f(2)和f(1),遞歸樹才終止。

    因此,青蛙跳階,遞歸解法的時間復雜度 等于O(1) * O(2?)=O(2?)

    C語言如何解決青蛙跳臺階問題

    你仔細觀察這顆遞歸樹,你會發(fā)現(xiàn)存在「大量重復計算」;

    比如f(4)被計算了兩次,f(3)被重復計算了3次&hellip;所以這個遞歸算法低效的原因,就是存在大量的重復計算!

    所以我們可以對代碼進行優(yōu)化

    遞歸升級

    在遞歸法的基礎(chǔ)上,新建一個長度為n的數(shù)組,用于在遞歸時存儲f(0)至f(n) 的數(shù)字值,重復遇到某數(shù)字時則直接從數(shù)組取用,避免了重復的遞歸計算。

    所以我們設(shè)置一個數(shù)組,用于存放第一次計算某一個n的jump(n)。

    當每一次要計算一個jump(n)的時候,就先查看數(shù)組中以n為下標的地方是否有值,有的話就可以不調(diào)用jump(n),而直接從數(shù)組中取得結(jié)果值,否則再計算jump(n)。

    代碼實現(xiàn)

    #include <stdio.h>
    
    long int f[1000]={0};
    int jump(int n){
        //當只有一階臺階的時候,只有一種上臺階的方式。
        
        //當有2階臺階的時候,有2種上臺階的方式,一種是一次上一階,還有一種是一次上2個臺階。
        
        //現(xiàn)在設(shè)有n階臺階,如果n>2,那種應(yīng)該有(先跳一階)+(先跳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("請輸入一個臺階數(shù):> ");
        scanf("%d", &num);
    
        int ret = jump(num);
    
        printf("小青蛙有 %d種 跳法\n", ret);
        return 0;
    }

    運行結(jié)果

    C語言如何解決青蛙跳臺階問題

    動態(tài)規(guī)劃解法

    很快我又發(fā)現(xiàn),不必把所有的記錄都記起來;

    假設(shè)我有3階樓梯,我只需要知道跳2階和跳1階的方法數(shù)是多少就可以算出跳3階的方法數(shù);

    因此每次只需要保留n&minus;1階和n&minus;2階的方法數(shù)。

    代碼實現(xiàn)

    #include <stdio.h>
    
    int jump(int n)
    {
        //n=0、1、2的時候,直接返回n即可
        if (n < 3)
        {
            return n;
        }
        
        //第一個數(shù)為1
        int one = 1;
    
        //第二個數(shù)為2
        int two = 2;
    
        //用于存放前兩個數(shù)之和
        int sum = 0; 
        while (n > 2)
        {
            sum = one + two;
            one = two;
            two = sum;
    
            n--;
        }
        return sum;
    }
    
    int main()
    {
        int num = 0;
        printf("請輸入一個臺階數(shù):> ");
        scanf("%d", &num);
    
        int ret = jump(num);
    
        printf("小青蛙有 %d種 跳法\n", ret);
        return 0;
    }

    運行結(jié)果

    C語言如何解決青蛙跳臺階問題

    2. 問題升級

    題目描述

    一只青蛙一次可以跳上一級臺階,也可以跳上二級臺階&hellip;&hellip;,也可以跳n級,求該青蛙跳上一個n級的臺階總共需要多少種跳法。

    解題思路

    一只青蛙要想跳到n級臺階,可以從一級,二級&hellip;&hellip;,也就是說可以從任何一級跳到n級

    C語言如何解決青蛙跳臺階問題

    當臺階為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&minus;1)+f(n&minus;2)+&hellip;&hellip;+f(2)+f(1)+f(0)

    最后這個f(0)是可以去掉的,因為0級就相當于沒跳,所以f(0)=0

    然后我們把f(0)去掉再轉(zhuǎn)換一下:f(n&minus;1)=f(n&minus;2)+f(n&minus;3)+&hellip;&hellip;+f(2)+f(1);

    推導過程

    我們列兩個等式:

    ①f(n)=f(n&minus;1)+f(n&minus;2)+f(n&minus;3)+&hellip;+f(2)+f(1)

    ②f(n&minus;1)=f(n&minus;2)+f(n&minus;3)+&hellip;+f(2)+f(1)

    由①-②得,f(n)=2f(n&minus;1)

    代碼實現(xiàn)

    遞歸方法

    代碼示例

    int jump(int n)
    {
        if (n == 1)
        {
            return 1;
        }
        else
        {
            return 2 * jump(n - 1);
        }
    }
    
    int main()
    {
        int num = 0;
        printf("請輸入一個臺階數(shù):> ");
        scanf("%d", &num);
    
        int ret = jump(num);
    
        printf("小青蛙有 %d種 跳法\n", ret);
        return 0;
    }

    運行結(jié)果

    C語言如何解決青蛙跳臺階問題

    非遞歸方法

    當然這里也可以用非遞歸的方式來實現(xiàn)

    那么非遞歸怎么去思考呢?

    可以這樣理解:

    C語言如何解決青蛙跳臺階問題

    然后使用用函數(shù)pow(2,n -1),需要加頭文件<math.h>

    但是我們這里可以不用庫函數(shù)來實現(xiàn),給大家介紹一種神奇的運算

    代碼示例

    int jump(int n)
    {
        if (n == 1)
        {
            return 1;
        }
        else
        {
            return 1 << (n-1);
        }
    }
    
    int main()
    {
        int num = 0;
        printf("請輸入一個臺階數(shù):> ");
        scanf("%d", &num);
    
        int ret = jump(num);
    
        printf("小青蛙有 %d種 跳法\n", ret);
        return 0;
    }

    運行結(jié)果

    C語言如何解決青蛙跳臺階問題

    我這里選擇用<<左移操作符來計算

    以上是“C語言如何解決青蛙跳臺階問題”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

    向AI問一下細節(jié)

    免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI