Leetcode 70. 爬樓梯 Java
阿新 • • 發佈:2018-12-11
假設你正在爬樓梯。需要 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 階
根據題意不難看出這是一道動態規劃的題目,只要寫出狀態轉移方程,我們就可以很容易的將其解決,誠然這道題的狀態轉移方程很簡單,那麼遇到更難的題目呢?在這裡想和大家通過一道例題來分析一下對於這類問題的解決思路。
首先,無從下手的話,我們不妨嘗試暴力遞迴
private int getClimbStairs(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return getClimbStairs(n - 1) + getClimbStairs(n - 2);
}
這樣的程式碼思路很清晰,在我們的編譯器上,也會輕鬆通過,但是提交到leetcode往往會提示超出時間限制,是因為在n大的時候,遞迴棧非常之深,每次去遞迴時間開銷很大,所以會丟擲超時。那麼怎麼去在這個思路上去改進呢? 有的同學可能會發現,在遞迴的時候,不斷有重複的遞迴,比如10會9和8 9會有8和7 這時8已經出現了兩次 而相面更小的數字會有更多的重複,那麼我們把這些資料儲存下來,方便呼叫不是可以節省開銷?
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了,同時,也得到了這個題目的狀態轉移方程:memo[i] = memo[i - 1] + memo[i - 2],有了狀態轉移方程,我們就可以遞推的去解決問題。
public int climbStairs(int n) {
int[] memo= new int[n + 1];
Arrays.fill(memo, -1);
memo[0] = 1;
memo[1] = 1;
for (int i = 2; i <= n; i++)
memo[i] = memo[i - 1] + memo[i - 2];
return memo[n];
}
這道題目本身很簡答,但是遇到困難問題時,希望這種先從上往下記憶化搜尋在從下往上層層遞推的思路,可以幫到同學們。