LeetCode演算法題-Climbing Stairs(Java實現)
這是悅樂書的第159次更新,第161篇原創
01 看題和準備
今天介紹的是LeetCode演算法題中Easy級別的第18題(順位題號是70)。你正在爬樓梯,它需要n步才能達到頂峰。每次你可以爬1或2步,你可以通過多少不同的方式登頂?注意:給定n是一個正整數。例如:
輸入:2
輸出:2
說明:有兩種方法可以爬到頂端
1、1步 + 1步
2、2步
輸入:3
輸出:3
說明:有三種方法可以爬到頂端
1、1步 + 1步 + 1步
2、1步 + 2步
3、2步 + 1步
輸入:4
輸出:5
說明:有5種方法可以爬到頂端
1、1步 + 1步 + 1步 + 1步
2、1步 + 1步 + 2步
3、1步 + 2步 + 1步
4、2步 + 1步 + 1步
5、2步 + 2步
本次解題使用的開發工具是eclipse,jdk使用的版本是1.8,環境是win7 64位系統,使用Java語言編寫和測試。
02 第一種解法
關於題目,可以從簡單的條件開始推導。
當n等於1的時候,有1種方式。
當n等於2的時候,有2種方式。
當n等於3的時候,有3種方式。
當n等於4的時候,有5種方式。
當n等於5的時候,有8種方式。
看到這,你會發現從n等於2開始,後一項等於前兩項的和,這時很容易想到遞迴,於是就有了第一種解法。
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return climbStairs(n-1) + climbStairs(n-2);
}
03 第二種解法
上面的解法,你應該也發現問題了,執行太慢了。有什麼可以優化的呢?既然只是求前兩個數的和,那麼可以引用陣列來存值,而不是每次都來重新算一次。
public int climbStairs2(int n) { int[] arr = new int[n+1]; return climb(n, arr); } public int climb(int n, int[] arr){ if (n == 0 || n == 1) { return 1; } else if(arr[n] > 0) { return arr[n]; } arr[n] = climb(n-1, arr) + climb(n-2, arr); return arr[n]; }
在climb方法裡判斷裡,是要加上else if那個判斷的,目的是避免重複計算,不判斷的話就和第一種差不多了。
04 第三種解法
既然利用陣列來存值,那麼是不是可以省掉遞迴?直接拿陣列元素返回結果就行。
public int climbStairs3(int n) {
int[] arr = new int[n+1];
arr[0] = 1;
arr[1] = 1;
for (int i=2; i<arr.length; i++) {
arr[i] = arr[i-1]+arr[i-2];
}
return arr[n];
}
05 三種解法對比
為了驗證哪種解法花費的時間更少,編寫了一些簡易的測試程式碼。
public static void main(String[] args) {
Easy_070_ClimbingStairs instance = new Easy_070_ClimbingStairs();
int arg = 44;
long start = System.nanoTime();
int result = instance.climbStairs(arg);
long end = System.nanoTime();
System.out.println("climbStairs---輸入:"+arg+" , 輸出:"+result+" , 用時:"+(end-start)/1000+"微秒");
System.out.println("----------------------------");
long start2 = System.nanoTime();
int result2 = instance.climbStairs2(arg);
long end2 = System.nanoTime();
System.out.println("climbStairs2---輸入:"+arg+" , 輸出:"+result2+" , 用時:"+(end2-start2)/1000+"微秒");
System.out.println("----------------------------");
long start3 = System.nanoTime();
int result3 = instance.climbStairs3(arg);
long end3 = System.nanoTime();
System.out.println("climbStairs3---輸入:"+arg+" , 輸出:"+result3+" , 用時:"+(end3-start3)/1000+"微秒");
}
下面是執行的結果
climbStairs---輸入:44 , 輸出:1134903170 , 用時:2795896微秒
----------------------------
climbStairs2---輸入:44 , 輸出:1134903170 , 用時:9微秒
----------------------------
climbStairs3---輸入:44 , 輸出:1134903170 , 用時:6微秒
可以看出來,第三種解法是最優的,遞迴是好演算法,但是會造成很多重複計算,影響速度,需要分場景來使用遞迴演算法。
06 小結
以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!