LeetCode70——爬樓梯

題目描述

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

思路

每次可以爬 1 或 2 個臺階。當我們爬 4 個臺階時,就是爬 3 個臺階的方法數,加上爬 2 個臺階的方法數,等於 F(3) + F(2) = 3 + 2 = 5。所以當我們爬 N 個臺階,就有 F(N - 1) + F(N - 2) 種方法。

解決方案

方案一:暴力破解

我們可以用遞歸的方法得到所有小於N的方法數,並把它們相加得出結果。遞歸結束的標誌爲 N=1 或 N =2。

var climbStairs = function(n) {
    if (n == 1) return 1
    if (n == 2) return 2
    return climbStairs(n - 1) + climbStairs(n - 2)
};

時間複雜度 O(2^n)。這種暴力解題的方法會超出時間限制,顯然不是我們想要的。

方案二:優化暴力破解

從上一種方法我們可以發現,每一步的結果都做了上一步的重複計算。比如F(6) + F(5) 後會計算 F(5) + F(4),F(5) 我們已經計算過了,就不要重複計算了。所以我們可以用一個數組來儲存計算結果,方便重複利用。

var climbStairs = function(n) {
    let arr = []
    function climb(n) {
        if (n == 1) return 1
        if (n == 2) return 2
        if (arr[n] > 0) return arr[n]
        
        arr[n] = climb(n - 1) + climb(n - 2)
        return arr[n]
    }
    return climb(n)
};

時間複雜度 O(n),優化之後提高了速度,已經不會超出時間限制了。

方案三:問題分解

和遞歸的思路一樣,把一個大問題分解成多個小問題,只是這次我們使用循環的方式,減少內存的開銷。

var climbStairs = function(n) {
    if (n == 1) return 1
    if (n == 2) return 2

    let arr = []
    arr[1] = 1
    arr[2] = 2
    for (let i = 3; i<= n; i++) {
        arr[i] = arr[i - 1] + arr[i - 2]
    }
    return arr[n]
};

時間複雜度 O(n),優化了內存的消耗,速度沒有提升。

方案四:斐波那契數

從上一個方案我們可以看出這是一個斐波那契數列。

var climbStairs = function(n) {
    if (n == 1) return 1
    if (n == 2) return 2
    
    let first = 1
    let second = 2
    for (let i = 3; i<= n; i++) {
        let third = first + second
        first = second
        second = third
    }
    return second
};

時間複雜度 O(n)

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