聲明:
作者不是什麼大佬,只是想寫寫算法,提高一下自己的內功。所以代碼可能會非常凌亂,(大佬們就當個笑話看就可以了),但我會認真註釋。
最後如果有路過的大佬,希望可以留下你們的建議和看法,謝謝!
70. 爬樓梯
一、原題鏈接
二、題目介紹
假設你正在爬樓梯。需要 n 階你才能到達樓頂。每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
注意:
給定n是一個正整數
三、測試用例
1.示例
輸入: 3
輸出: 3
解釋: 有三種方法可以爬到樓頂。
1 階 + 1 階 + 1 階
1 階 + 2 階
2 階 + 1 階
四、思路解析
這道題算是比較簡單的動態規劃的題。如果不知道什麼是動態規劃,可以到這個知乎回答上瞅一眼。什麼是動態規劃
而且這道臺階問題其實和湊錢問題幾乎一樣,如果改成最少需要幾步到達樓頂,不論的題的難度,解法上也是完全一致。
- 首先我們先假設現在走到了5
- 那麼5前有兩種走法從4走一步與從3走兩步
- 而4和3 也有有不同的方式走上來,根據第二步邏輯持續遞歸
- 最後將每條分支深入到0,其中每一條從0到5的支路就是一條路徑
那麼第i個結點的路徑怎麼算,我們可以人任取結點,發現其實就是左右結點的路徑相加。最終我們可以列出方程dp(i) =dp(i-1)+dp(i-2)且i>=0
當然後面的且條件我們可以通過邊界if加以規定
五、代碼
優點:自上而下,容易結合上述圖解進行學習
缺點:遞歸與重複操作,導致耗時太長,甚至會導致算法無法通過
// 遞歸算法
public int down(int n){
// 遍歷到0的時候說明已經形成了一條路徑了,返回 1
if(n==0){
return 1;
}else if(n>0) {
// 一般狀態的遞歸調用 也是dp算法的體現dp(n) = dp(n-1)+dp(n-2)
return down(n-1)+down(n-2);
}else {
// 其他情況直接返回0
return 0;
}
}
public int climbStairs(int n) {
// 如果是0 直接就是0了不用走了
if(n==0){
return 0;
}
// 開始遞歸計算
int sum = down(n);
return sum;
}
核心還是:dp(i)=dp(i-1)+dp(i-2),我們可以看作成類似斐波那契數列來做
優點:完全解決了上述的操作,時間大大縮短
缺點:根據圖解需要把頂層遞歸轉化位底層循環,如果不熟練的話很有可能會寫不出來
public int climbStairs(int n) {
// n爲0直接返回0
if (n == 0) {
return 0;
}
// n == 1 直接一種
else if (n == 1) {
return 1;
}
// n == 2 固定兩種
else if(n==2){
return 2;
}else {
//有了dp(1)和dp(2)的鋪墊,就可以當作斐波那契數列計算
//上一層的最優 dp(i-1)
int last = 2;
//上上一層的最優 dp(i-2)
int last_last = 1;
// 循環操作
for (int i = 3; i <= n; i++) {
int temp = last;
// dp方程的體現
last = last_last+last;
last_last = temp;
}
// 返回
return last;
}
}