力扣 - 劍指 Offer 10- II. 青蛙跳臺階問題
阿新 • • 發佈:2021-11-27
題目
思路1(遞迴 / 自頂向下)
這題就是和上一題劍指 Offer 10- I. 斐波那契數列基本一模一樣,都是 fib(n) = fib(n-1) + fib(n-2)
這個遞推公式,只是初始條件不一樣啦:上一題是 0、1、1、2...
,而本題是 1、1、2、3、5...
-
這題是很常見的一道入門遞迴題,可以採用自頂向下的遞迴方法,比如我們要求第
n
個位置的值,根據斐波那契數列的定義fib(n) = fib(n-1) + fib(n-2)
,即等於前一個和前前一個兩個的值之和 -
但是如果直接遞迴,會導致很多重複的計算,效率很低,比如
n
為 5 時:-
fib(5)
為fib(4)
和fib(3)
兩個值之和 -
然後
fib(4)
又等於fib(3)
和fib(2)
兩個值之和。注意,fib(3)
在上一步已經求過了,這裡還要再求一次 -
另一個
fib(3)
即為fib(2)
和fib(1)
兩個值之和,同樣,fib(2)
,也被求過了 -
……
-
-
根據上面例子我們可以發現這樣子會導致很多多餘的計算,做無用功,也會出現由於
n
的增大導致計算量急劇增大。因此我們可以將這個演算法優化一下,就是新增一個表格memory
來記錄計算過的值,在每次遞迴的時候,判斷一下之前是否計算過了,如果發現計算過了,直接返回陣列中對應的值,否則就計算一下,然後記錄到memory
程式碼
class Solution { int[] memory; public int numWays(int n) { memory = new int[n+1]; return help(n); } public int help(int n) { // 遞迴結束的條件 if (n <= 1) { return 1; } // 判斷是否計算過了 if (memory[n] != 0) { return memory[n]; } // 沒有在 memory 中找到就計算一下,然後在記錄到 memory 中 int i = help(n - 1) + help(n - 2); i %= 1000000007; memory[n] = i; return memory[n]; } }
複雜度分析
- 時間複雜度:\(O(N)\)
- 空間複雜度:\(O(N)\)
思路2(迭代 / 動態規劃)
- 同樣,根據斐波那契數列定義,可以發現第
n
個的值為前兩個值之和,因此我們可以從第一個開始計算,迴圈計算到n
就得到了結果,空間上僅僅佔兩個變數的空間,為 \(O(1)\) ,程式碼如下:
程式碼
class Solution {
public int numWays(int n) {
if (n <= 1) {
return 1;
}
int a = 1;
int b = 2;
for (int i = 2; i < n; i++) {
int temp = (a + b);
a = b;
b = temp;
b %= 1000000007;
}
return b;
}
}
複雜度分析
- 時間複雜度:\(O(N)\)
- 空間複雜度:\(O(1)\)