問題描述
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?
Note: Given n will be a positive integer.
你正在爬樓梯。需要n步才能到達頂端。
每次你可以爬1或2級臺階。你可以用多少種不同的方式爬到山頂?
注意:給定n是一個正整數。
例子1:
輸入: 2
輸出: 2
期待結果: 存在兩種方式爬到最頂端
1. 1 步 + 1 步
2. 2 步
例子2:
輸入: 3
輸出: 3
期待結果: 存在三種方式爬到最頂端
1. 1 步 + 1 步 + 1 步
2. 1 步 + 2 步
3. 2 步 + 1 步
Python 實現
其實這是一個很經典的算法題,乍看之下不知道從何下手,但我們可以換個角度來看:從結果出發。
根據題目可知,每次行動只有兩種可能,要麼爬 1 級臺階,要麼爬 2 級臺階,所以我們可以這麼來思考:假設到達第 n 個臺階共有 f(n) 種方式,則
- 到達第 n 個臺階,要麼從 第 n-1 個臺階爬 1 級臺階到達,要麼從 第 n-2 個臺階爬 2 級臺階到達。到達第 n-1 個臺階共有 f(n-1) 種方式,到達第 n-2 個臺階共有 f(n-2) 種方式,所以 f(n) = f(n-1) + f(n-2);
- 到達第 n-1 個臺階,要麼從 第 n-2 個臺階爬 1 級臺階到達,要麼從 第 n-3 個臺階爬 2 級臺階到達。到達第 n-2 個臺階共有 f(n-2) 種方式,到達第 n-3 個臺階共有 f(n-3) 種方式,所以 f(n-1) = f(n-2) + f(n-3);
- 。。。
顯然,這個問題的答案就是一個斐波拉契數列了。斐波拉契數列的表達式:f(n) = f(n-1) + f(n-2)。
在該問題中,兩個基礎條件是 f(2) = 2,f(1) = 1。
因此,最後代碼實現一個斐波拉契數列就可以了。
實現一:遞歸實現
這種實現方式很直觀,但是有經驗的朋友都知道,在這個過程中,有些結果被重複計算,浪費的計算資源。例如
- f(n) = f(n-1) + f(n-2)
- f(n-1) = f(n-2) + f(n-3)
在這裏 f(n-2) 就被重複計算了兩遍。不僅如此,當 n 的值特別大的時候,使用遞歸實現很可能因爲函數調用次數過多,從而導致棧溢出。因此,實現斐波拉契數列常常使用下面第二種方法。
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
if n == 2:
return 2
# May be stack overloaded.
return self.climbStairs(n-1) + self.climbStairs(n-2)
實現二:數組(列表)實現
斐波拉契數列實際上從 1 到 n 分別對應一個結果值,因此使用數組或者列表來記錄結果最直觀。
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
if n == 2:
return 2
F = [1, 2]
for i in range(n-2):
F.append(F[-1] + F[-2])
return F[-1]
實現三:直接獲取結果
同樣是斐波拉契數列的一種實現形式,由於我們只需要獲取值爲 n 時的結果,因此通過分析得到基礎條件的值(f(2) = 2, f(1) = 1)之後,我們可以直接通過斐波拉契數列的計算公式,算出最後 f(n) 的值返回即可,這樣就可以避免使用數組或者列表記錄中間值,以節省內存空間。
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
if n == 1:
return 1
if n == 2:
return 2
s = 0
a = 2
b = 1
for i in range(n-2):
s = a + b
b = a
a = s
return s