1. 程式人生 > >LeetCode演算法題-Climbing Stairs(Java實現)

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 小結

以上就是全部內容,如果大家有什麼好的解法思路、建議或者其他問題,可以下方留言交流,點贊、留言、轉發就是對我最大的回報和支援!