[每日一題] 第十七題:青蛙跳臺階問題

DRose發表於2020-07-31

一隻青蛙一次可以跳上1級臺階,也可以跳上2級臺階。求該青蛙跳上一個 n 級的臺階總共有多少種跳法。

答案需要取模 1e9+7(1000000007),如計算初始結果為:1000000008,請返回 1。

示例 1:

輸入:n = 2
輸出:2

示例 2:

輸入:n = 7
輸出:21

提示:

  • 0 <= n <= 100

方法一:我的做法

本題很容易看出是遞迴方法來,同斐波那契數列很相似。

這裡我列出幾個注意事項:

  1. F(0)=1,F(1)=1
  2. F(N) = F(N-1) + F(N-2)
  3. 要把之前的結果儲存下來,這樣就不會重複計算
  4. 答案一定記得要取模,不然無法通過

程式碼

class Solution {
    public int numWays(int n) {
        if (n <= 1) {
            return 1;
        }
        int[] nums = new int[n+1];
        nums[0] = 1;
        nums[1] = 1;

        int current = 2;

        while (current <= n) {
            nums[current] = (nums[current-1] + nums[current-2]) % 1000000007;
            current++;
        }

        return nums[n];
    }
}

複雜度

時間複雜度 O(N):計算 f(n) 需迴圈 n 次,每輪迴圈內計算操作使用 O(1) 。
空間複雜度 O(N):因為新建立了個 nums 陣列,需要額外的 N 個空間

方法二:動態規範

解題思路:

此類求多少種可能性的題目一般都有 遞推性質,即 f(n) 和 f(n-1) …… f(1) 之間是有聯絡的。

  • 設跳上 n 級臺階有 f(n) 種跳法,在所有跳法中,青蛙的最後一步只有兩種情況,跳上 1 級或 2 級臺階

    1. 當為 1 級臺階: 剩 n - 1 個臺階,此情況共有 f(n-1) 種跳法;
    2. 當為 2 級臺階: 剩 n - 2 個臺階,此情況共有 f(n-2) 種跳法。
  • f(n) 為以上兩種情況之和,即 f(n) = f(n-1) + f(n-2),以上遞推性質為斐波那契數列。本題可轉化為求斐波那契數列第 n 項的值,但起始數字不同。

    • 青蛙跳臺階問題:f(0)=1,f(1)=1,f(2)=2
    • 斐波那契數列問題:f(0)=0,f(1)=1,f(2)=1

[每日一題] 第十七題:青蛙跳臺階問題

斐波那契數列的定義是 f(n + 1) = f(n) + f(n - 1) ,生成第 n 項的做法有以下幾種:

  1. 遞迴法:
    原理: 把 f(n) 問題的計算拆分成 f(n−1) 和 f(n−2) 兩個子問題的計算,並遞迴,以 f(0) 和 f(1) 為終止條件。
    缺點: 大量重複的遞迴計算,例如 f(n) 和 f(n−1) 兩者向下遞迴都需要計算 f(n−2) 的值。
  2. 記憶化遞迴法:
    原理: 在遞迴法的基礎上,新建一個長度為 n 的陣列,用於在遞迴時儲存 f(0) 至 f(n) 的數字值,重複遇到某數字時則直接從陣列取用,避免了重複的遞迴計算。
    缺點: 記憶化儲存的陣列需要使用 O(N) 的額外空間。
  3. 動態規劃:
    原理: 以斐波那契數列性質 f(n+1)=f(n)+f(n−1) 為轉移方程。
    從計算效率、空間複雜度上看,動態規劃是本題的最佳解法。

動態規劃解析:

  • 狀態定義: 設 dp 為一維陣列,其中 dp[i] 的值代表 斐波那切數列第 i 個數字
  • 轉移方程: dp[i+1] = dp[i] + dp[i-1],即對應數列定義 f(n+1)=f(n)+f(n-1);
  • 初始狀態: dp[0] = 1,dp[1] = 1,即初始化前兩個數字;
  • 返回值: dp[n],即斐波那切數列第 n 個數字。

空間複雜度優化:

若新建長度為 n 的 dp 列表,則空間複雜度為 O(N)。

  • 由於 dp 列表第 i 項只與第 i-1 和 第 i-2 項有關,因此只需要初始化三個整形變數,sumab,利用輔助變數 sum 使 a,b兩數字交替前進即可(具體實現見程式碼)。
  • 因為節省了 dp 列表空間,因此空間複雜度降至 O(1)。

迴圈求餘法:

大數越界,隨著 n 增大,f(n) 會超過 Int32 甚至 Int64 的取值範圍,導致最終的返回值錯誤。

求餘運算規則: 設正整數 x,y,p,求餘符號為 ⊙ ,則有 (x+y)⊙p=(x⊙p+y⊙p)⊙p 。
解析: 根據以上規則,可推出 f(n)⊙p = [f(n−1)⊙p+f(n−2)⊙p]⊙p ,從而可以在迴圈過程中每次計算 sum=a+b⊙1000000007 ,此操作與最終返回前取餘等價。

複雜度:

時間複雜度 O(N):計算 f(n) 需迴圈 n 次,每輪迴圈內計算操作使用 O(1) 。
空間複雜度 O(1):幾個標誌變數使用常數大小的額外空間。

解法來源

作者:jyd
連結:leetcode-cn.com/problems/qing-wa-t...
來源:力扣(LeetCode)

來源:力扣(LeetCode)
連結:leetcode-cn.com/problems/qing-wa-t...
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章