1. 程式人生 > >領扣-70 爬樓梯 Climbing Stairs MD

領扣-70 爬樓梯 Climbing Stairs MD

distinct enter leetcode 時間 position public arr mark ali

Markdown版本筆記 我的GitHub首頁 我的博客 我的微信 我的郵箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 [email protected]

領扣-70 爬樓梯 Climbing Stairs MD


目錄

目錄
爬樓梯 Climbing Stairs
題目
遞歸方式
動態規劃
優化

爬樓梯 Climbing Stairs

題目

假設你正在爬樓梯。需要 n 階你才能到達樓頂。
You are climbing a stair case. It takes n steps to reach to the top.

每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

註意:給定 n 是一個正整數。
Note: Given n will be a positive integer.

示例 1:

輸入: 2
輸出: 2
解釋: 有兩種方法可以爬到樓頂。
1.  1 階 + 1 階
2.  2 階

示例 2:

輸入: 3
輸出: 3
解釋: 有三種方法可以爬到樓頂。
1.  1 階 + 1 階 + 1 階
2.  1 階 + 2 階
3.  2 階 + 1 階

遞歸方式

這個題目跟斐波那契數列非常相似,假設梯子有n層,那麽如何爬到第n層呢?
因為每次只能爬1或2步,那麽爬到第n層的方法要麽是從第 n-1 層一步上來的,要不就是從 n-2 層2步上來的,所以遞推公式非常容易的就得出了:dp[n] = dp[n-1] + dp[n-2]

class Solution {
    public int climbStairs(int n) {
        if (n == 1) return 1;
        if (n == 2) return 2;
        return climbStairs(n - 1) + climbStairs(n - 2);
    }
}

這樣的代碼思路很清晰,在我們的編譯器上,也會輕松通過,但是提交到leetcode往往會提示超出時間限制,是因為在n大的時候,遞歸棧非常之深,每次去遞歸時間開銷很大,所以會拋出超時。

那麽怎麽去在這個思路上去改進呢?

有的同學可能會發現,在遞歸的時候,不斷有重復的遞歸,比如10會有9和8 9會有8和7 這時8已經出現了兩次,而下面更小的數字會有更多的重復,那麽我們把這些數據存儲下來,方便調用不是可以節省開銷?

class Solution {
    private int[] memo;

    public int climbStairs(int n) {
        memo = new int[n + 1];
        Arrays.fill(memo, -1);
        return getClimbStairs(n);
    }

    private int getClimbStairs(int n) {
        if (n == 1) return 1;
        if (n == 2) return 2;
        if (memo[n] == -1) memo[n] = getClimbStairs(n - 1) + getClimbStairs(n - 2);
        return memo[n];
    }
}

我們只需要聲明一個 memo 數組,把遞歸中間過程的值存儲下來就好,可以大大的提高效率,這時候提交給 leetcode 已經可以獲得AC了

動態規劃

class Solution {

    public int climbStairs(int n) {
        int[] memo = new int[n + 1];
        memo[0] = 1;
        memo[1] = 2;

        for (int i = 2; i <= n; i++) {
            memo[i] = memo[i - 1] + memo[i - 2];
        }
        return memo[n - 1];
    }
}

優化

我們可以對空間進行優化,我們只用幾個整型變量來存儲過程值,來模擬上面累加的過程,而不用存儲所有的值,參見代碼如下:

class Solution {
    public int climbStairs(int n) {
        if (n == 1) return 1;
        if (n == 2) return 2;

        int a1 = 1, a2 = 2, a3 = 0;
        while (n-- > 2) {
            a3 = a1 + a2;
            a1 = a2;
            a2 = a3;
        }
        return a3;
    }
}

上述邏輯可以優化為:

class Solution {
    public int climbStairs(int n) {
        if (n == 1) return 1;
        if (n == 2) return 2;

        int a = 1, b = 2;
        while (n-- >= 2) {
            b += a; //相加的值
            a = b - a; //原來的 b
        }
        return a + b;
    }
}

或者這樣:

class Solution {
    public int climbStairs(int n) {
        int a = 1, b = 1;
        while (n-- > 0) {
            b += a; //相加的值
            a = b - a; //原來的 b
        }
        return a;
    }
}

2018-12-7

領扣-70 爬樓梯 Climbing Stairs MD