【劍指Offer】變態跳臺階

題目描述

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

解法1

本題是【劍指Offer】跳臺階的進化版本。
原來的青蛙只可以跳上1級或2級,即F(n) = F(n - 1) + F(n - 2)
現在的青蛙可以跳上1到n的任意級,按照之前的解題思路,依然先來看F(n),對於一個n級臺階來說
青蛙第一次可以跳1級,則還剩n - 1級臺階,即F(n - 1)
青蛙第一次可以跳2級,則還剩n - 2級臺階,即F(n - 2)

青蛙第一次可以跳n - 1級,則還剩1級臺階,即F(1)
青蛙第一次可以跳n級,即1種跳法
則F(n) = F(n - 1) + F(n - 2) + F(n - 3) + F(n - 4) + … + F(1) + 1
很顯然F(1)= 1,在已知F(1)的情況下,我們可以利用遞歸解這道題,代碼如下

實現代碼

public int jumpFloorII(int number)
{
    int count = 1;
    for (int i = 1; i < number; i++)
    {
        count = count + jumpFloorII(number - i);
    }
    return count;
}

解法2

本題的遞歸算法由於編譯器的低效實現不可避免的會存在大量的重複運算,我們可以在遞歸的基礎上做一些優化,詳細說明可以查看【劍指Offer】斐波那契數列。或者換一種思路,我們也可以不使用遞歸。有時候列出結果的前幾項,找找規律,可能會有意想不到的收穫
對於1級臺階,青蛙只有1 = 20種跳法
對於2級臺階,青蛙有2 = 21種跳法(分別是{1,1}, {2})
對於3級臺階,青蛙有4 = 22種跳法(分別是{1,1,1}, {1,2}, {2,1}, {3})
對於4級臺階,青蛙有8 = 23種跳法(分別是{1,1,1,1}, {1,1,2}, {1,2,1}, {2,1,1}, {2,2}, {1,3}, {3,1}, {4})

不難發現,對於n級臺階,總跳法數是2n-1
當然我們也可以通過公式推導出這個結果
由解法1可知
F(n) = F(n - 1) + F(n - 2) + F(n - 3) + F(n - 4) + … + F(1) + 1,則
F(n - 1) = F(n - 2) + F(n - 3) + F(n - 4) + … + F(1) + 1
兩個式子合併可得F(n) = 2F(n - 1),則
F(n - 1) = 2F(n - 2)
F(n - 2) = 2F(n - 3)
即F(n) = 22F(n - 2),F(n) = 23F(n - 3)
以此類推,F(n)= 2n-1F(n - (n - 1)) = 2n-1F(1) = 2n-1
最終這道題被轉換成如何求解2n-1,簡單的方法是對2連乘n-1次,繼續優化的話,可以使用整數的快速冪,【劍指Offer】斐波那契數列也已經有了詳細的詳解。下面僅放上本題的整數快速冪解法

實現代碼

public int jumpFloorII(int number)
{
    number = number - 1;
    int count = 1;
    int m = 2;
    while (number > 0)
    {
        if ((number & 1) > 0)
        {
            count *= m;
        }
        m = m * m;
        number = number >> 1;
    }
    return count;
}

解法3

對於求解2n-1,可以繼續優化,利用左移運算,只使用一行代碼就可以得到2n-1
對於數字1,左移1位是10,即2 = 21
左移2位是100,即4 = 22
左移3位是1000,即8 = 23
以此類推,左移n位,就是2n
要求2n-1,只需要將數字1左移n-1位,對應的代碼如下

實現代碼

public int jumpFloorII(int number)
{
    return 1 << (number - 1);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章