leetcode | 假設你正在爬樓梯。需要 n 階你才能到達樓頂。每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
阿新 • • 發佈:2021-01-08
假設你正在爬樓梯。需要 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
遞迴呼叫,暴力破解出每一種情況,然後把所有情況累計求和。
public int climbStairs(int n) {
if( n == 1 || n == 0 )
return 1;
return climbStairs(n - 1) + climbStairs(n - 2);
}
分析
程式碼比較簡潔易懂,但是程式碼本身是用遞迴實現的,所以需要消耗大量的記憶體空間,所以最後的執行結果超時了。
方案2
通過分析示例,我們可以發現它其實就是一個斐波那契數列,讓我們求第n個斐波那契數
public int climbStairs(int n) {
if(n==1) return 1;
int a = 1;
int b = 2;
int c;
for(int i=3;i<= n ;++i){
c = a + b;
a = b;
b = c;
}
return b;
}
分析
這樣寫只需要一個簡單的迴圈就可以解決問題,程式碼寫起來也比較簡單,而且結果不會超時的,但是這道題是屬於動態規劃的。
方案3
動態規劃解決這個問題。設dp[i]就是i時候的最多方案則
dp[1] = 1;
dp[2] = 2;
dp[3] = dp[2] + dp[1]
......
dp[n] = dp[n-1] + dp[n2]
public int climbStairs(int n) {
//這裡大小根據自己需要,或者使用 List 也可以
int[] dp = new int[100000];
dp[1] = 1;
dp[2] = 2;
for( int i = 3;i <= n;++i ){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
分析
這樣寫就很好的解決這個問題,在動態規劃的世界裡,只要找到遞推公式,那麼答案也就隨之出來了。
其他參考1
演算法 0ms
public int climbStairs(int n) {
int numsMax=0;
int num1=1;
int num2=2;
if(n==1){
return 1;
}
if(n==2){
return 2;
}
for(int i=3;i<=n;i++){
numsMax=num1+num2;
num1=num2;
num2=numsMax;
}
return numsMax;
}
其他參考2
本問題其實常規解法可以分成多個子問題,爬第n階樓梯的方法數量,等於 2 部分之和
倒數第二步爬上 n-1 階樓梯的方法數量。因為再爬1階就能到第n階
倒數第二步爬上 n-2 階樓梯的方法數量,因為再爬2階就能到第n階
所以我們得到公式
arr[n] = arr[n-1] + arr[n-2]
同時需要初始化
arr[1]=1 和 arr[2]=2
時間複雜度:O(n)
比如爬10級樓梯
則獲取到最後一步是 走1階的方法數量
跟獲取到最後一步是 走2階的方法數量
相加則為 總方法數量
/**
* @param {number} n
* @return {number}
*/
var climbStairs = function(n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
const 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];
};