1. 程式人生 > >LeetCode(53) Climbing Stairs (劍指Offer->跳臺階、變態跳臺階)

LeetCode(53) Climbing Stairs (劍指Offer->跳臺階、變態跳臺階)

Climbing Stairs (跳臺階)

題目描述

You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

本題對應了《劍指offer》上的跳臺階
一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法。

題目解法

本題是一道很典型的遞迴題目,根據題目的初始條件可知:

  • f(1) = 1;
  • f(2) = 2;
  • f(n) = f(n-1) + f(n-2) (n > 2)

對於n個臺階時的解釋是,最後青蛙可以一次跳一個臺階,則解法是f(n-1);也可以直接跳兩個臺階,則解法是f(n-2)。

其實到這裡大家可以發現本題和斐波拉切數列的思路相同,不同點僅僅在於初始條件,因此可以使用遞迴得到結果。然而本題的遞迴過程中會涉及到太多的重複計算。因為在計算f(n)的時候需要計算f(n-1)和f(n-2),而在計算f(n-1)時本身也是需要計算f(n-2)的。所以還是不採用遞迴的方式,使用兩個變數分別表示為f(n-1)和f(n-2)並更新這兩個變數,從而得到最終結果。

class Solution {
public:
    int climbStairs(int n) {
        if(n <= 2) return n;
        int first = 1;
        int second = 2;
        for(size_t i = 3; i <= n; ++i)
        {
            second = first + second;
            first = second - first;
        }
        return second;
    }
};

變態跳臺階

本題是在上一題的基礎上的升級版,來源於《劍指offer》

題目描述

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

解題思路

本題和第一題的思路相同,當然這題如果使用遞迴去做的話那麼迭代的時候重複的次數太多了,很可能會造成棧溢位。這裡我們使用輔助空間的辦法將遞迴變成迴圈。

class Solution {
public:
    int jumpFloorII(int number) {
        if(number <= 2) return number;
        vector<int> jump;
        jump.push_back(1);
        jump.push_back(2);
        for(int i = 2; i != number; ++i)
        {
            int floor = accumulate(jump.begin(), jump.end(), 0) + 1;
            jump.push_back(floor);
        }
        return jump[number-1];
    }
};

解法進階

上述做法每次對陣列進行求和效率也不高,可以進一步分析題意。當有n個臺階時,分析如下:
f(1) = 1
f(2) = f(2-1) + f(2-2) //f(2-2) 表示2階一次跳2階的次數。
f(3) = f(3-1) + f(3-2) + f(3-3)

f(n) = f(n-1) + f(n-2) + f(n-3) + … + f(n-(n-1)) + f(n-n)

  • 這裡的f(n) 代表的是n個臺階有一次1,2,…n階的 跳法數。
  • n = 1時,只有1種跳法,f(1) = 1
  • n = 2時,會有兩個跳得方式,一次1階或者2階,這回歸到了問題(1) ,f(2) = f(2-1) + f(2-2)

  • n = n時,會有n中跳的方式,1階、2階…n階,得出結論:f(n) = f(n-1)+f(n-2)+…+f(n-(n-1)) + f(n-n) => f(0) + f(1) + f(2) + f(3) + … + f(n-1)

  • 由以上已經是一種結論,但是為了簡單,我們可以繼續簡化:
  • f(n-1) = f(0) + f(1)+f(2)+f(3) + … + f((n-1)-1) = f(0) + f(1) + f(2) + f(3) + … + f(n-2)
  • f(n) = f(0) + f(1) + f(2) + f(3) + … + f(n-2) + f(n-1) = f(n-1) + f(n-1)
  • 可以得出: f(n) = 2*f(n-1)

得出最終結論,在n階臺階,一次有1、2、…n階的跳的方式時,總得跳法為f(n):

  • 1 ,(n=0 )
  • 1 ,(n=1 )
  • 2*f(n-1),(n>=2)

所以程式碼為:

public class Solution {
    public int JumpFloorII(int target) {
        if (target <= 0) {
            return -1;
        } else if (target == 1) {
            return 1;
        } else {
            return 2 * JumpFloorII(target - 1);
        }
    }
}

更簡單一點為:

public class Solution {
    public int JumpFloorII(int target) {
        return  1<<--number;
    }
}