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;
}
}