LeetCode刷題——70. 爬樓梯

題目

假設你正在爬樓梯。需要 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 階

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/climbing-stairs

思路

對於這樣一個問題,我們先來思考下能否遞歸的解決,它內部是否有遞歸的結構。

我們自頂向下的思考問題,直接考慮第nn階臺階,並且假設它下面的n1n-1階,n2n-2階等子問題都已經解決了。

如果我們要想爬上nn階臺階,因爲一次要麼爬11階,要麼爬22階,所以爬nn階臺階有兩種可能。

n1n-1階再爬11階或者從n2n-2階再爬22階。

在這裏插入圖片描述

不難看出這是一個遞歸問題,我們把問題轉換爲爬n1n-1階有多少種方法和爬n2n-2階有多少種方法。然後把這兩個問題的答案相加就好了。這樣把一個大的問題轉換爲兩個小問題。

在這裏插入圖片描述
用同樣的思路可以求出爬n1n-1階和爬n2n-2階的方法數。從上面這個遞歸樹可以看出,存在很多重複子問題。

下面我們先寫出按照這種思路解決問題的遞歸算法。

代碼

遞歸

class Solution:
    def climbStairs(self, n: int) -> int:
        # 遞歸的終止條件
        if n == 1:
            return 1
        if n == 2:
            return 2
        return self.climbStairs(n-1) + self.climbStairs(n-2)

在這裏插入圖片描述
雖然思路是對的,但是遞歸的方式是比較低效的,這裏導致了計算超時。參閱LeetCode刷題之動態規劃思想,我們可以將其改成記憶化搜索的方式,解決重疊子問題。

因爲爬2階臺階有2種方法,和斐波那契數列很像。這裏的遞歸終止條件還可以寫成

if n == 0:
    return 1
if n == 1:
   return 1

這樣這個問題就是斐波那契數列的應用。

記憶化搜索

dp = {}

class Solution:
    def climbStairs(self, n: int) -> int:
        # 遞歸的終止條件
        if n == 0:
            return 1
        if n == 1:
            return 1
        if n not in dp: # 如果沒有計算過再去計算
            dp[n] =  self.climbStairs(n-1) + self.climbStairs(n-2)
        return dp[n]

在這裏插入圖片描述
最後改成動態規劃也就很簡單了。

動態規劃

class Solution:
    def climbStairs(self, n: int) -> int:
        if n == 1:
            return 1
        dp = [1] * (n+1) #dp[0] = 1   ,    dp[1] = 1   ,dp[2]以後的通過下面的式子計算
        
        for i in range(2,n+1):
            dp[i] = dp[i-1] + dp[i-2]
        return dp[n]

動態規劃不需要遞歸求解,是一種自底向上的求解思想。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章