代码随想录算法训练营第38天|509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯

509. 斐波那契数

力扣题目链接

思路

动态规划

  • dp[i]的定义为:第i个数的斐波那契数值是dp[i]
  • 状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];
  • 初始化:dp[0] = 0; dp[1] = 1;
  • 从前往后遍历

矩阵快速幂

代码随想录算法训练营第38天|509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯_第1张图片

通项公式

代码随想录算法训练营第38天|509. 斐波那契数,70. 爬楼梯,746. 使用最小花费爬楼梯_第2张图片

代码

动态规划

class Solution {
public:
    int fib(int N) {
        if (N <= 1) return N;
        vector dp(N + 1);
        dp[0] = 0;
        dp[1] = 1;
        for (int i = 2; i <= N; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[N];
    }
};

优化

class Solution {
public:
    int fib(int n) {
        if (n == 0) return 0;
        if (n == 1) return 1;
        int f0 = 0, f1 = 1, f2;
        for (int i = 2; i <= n; i++){
            f2 = f0 + f1;
            f0 = f1;
            f1 = f2;
        }
        return f2;
    }
};
  • 时间复杂度O(n)
  • 空间复杂度O(1)

递归

class Solution {
public:
    int fib(int n) {
        if (n == 0) return 0;
        else if (n == 1) return 1;
        else return fib(n - 1) + fib(n - 2);
    }
};
  • 时间复杂度:O(2^n)
  • 空间复杂度:O(n)

矩阵快速幂

class Solution {
public:
    int fib(int n) {
        if (n < 2) return n;
        vector> q{{1, 1}, {1, 0}};
        vector> res = matrix_pow(q, n - 1);
        return res[0][0];
    }
    vector> matrix_pow(vector>& a, int n) {
         vector> ret{{1, 0}, {0, 1}}; // 单位矩阵
         while (n > 0) {
             if (n & 1) {
                 ret = matrix_multiply(ret, a);
             }
             n >>= 1;
             a = matrix_multiply(a, a);
         }
         return ret;
    }
    vector> matrix_multiply(vector>& a, vector>& b) {
        vector> c{{0, 0}, {0, 0}};
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 2; j++) {
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
            }
        }
        return c;
    }

};
  • 时间复杂度O(logn)
  • 空间复杂度O(1)

通项公式

class Solution {
    public int fib(int n) {
        double sqrt5 = Math.sqrt(5);
        double fibN = Math.pow((1 + sqrt5) / 2, n) - Math.pow((1 - sqrt5) / 2, n);
        return (int) Math.round(fibN / sqrt5);
    }
}

70. 爬楼梯

力扣题目链接

思路

动态规划常规解法可以分成多个子问题,爬第n阶楼梯的方法数量,等于2部分之和

  • 爬上n−1阶楼梯的方法数量。因为再爬1阶就能到第n阶
  • 爬上n−2阶楼梯的方法数量,因为再爬2阶就能到第n阶
  • 状态转移方程:dp[i] = dp[i - 1] + dp[i - 2]
  • 初始化dp[1] = 1; dp[2] = 2;

代码

class Solution {
public:
    int climbStairs(int n) {
        if (n == 1) return 1;
        int dp[4];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[3] = dp[2] + dp[1];
            dp[1] = dp[2];
            dp[2] = dp[3];
        }
        return dp[2];
    }
};
  • 时间复杂度O(n)
  • 空间复杂度O(1)

746. 使用最小花费爬楼梯

力扣题目链接

思路

  • dp[i] 表示走到第i阶楼梯的最小花费

  • 递推公式:dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);

    • 可以从下标 i - 1 花费 cost[i - 1] 到达 i
    • 可以从下边 i - 2 花费 cost[i - 2] 到达 i
    • 为了使总花费最小,选择两个方案花费最小的
  • 初始化:dp[0] =0; dp[1] = 0; 到达第0阶和第1阶不需要耗费体力,往上跳会耗费体力

  • 遍历顺序:从前往后

代码

class Solution {
public:
    /*
     * dp[i]表示走到第i阶楼梯的最小花费
     * 递推公式:dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
     * 初始化:dp[0] = cost[0]; dp[1] = 0;
     * 遍历顺序:从前往后
    */
    int minCostClimbingStairs(vector& cost) {
        vector dp(cost.size() + 1);
        dp[0] = 0;
        dp[1] = 0;
        for (int i=2; i <= cost.size(); i++) {
            dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
        }
        return dp[cost.size()];
    }
};
  • 时间复杂度O(n)
  • 空间复杂度O(n)

优化

class Solution {
public:
    /*
     * dp[i]表示走到第i阶楼梯的最小花费
     * 递推公式:dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
     * 初始化:dp[0] = 0; dp[1] = 0;
     * 遍历顺序:从前往后
    */
    int minCostClimbingStairs(vector& cost) {
        int dp0 = 0;
        int dp1 = 0;
        for (int i=2; i <= cost.size(); i++) {
            int dp2 = min(dp1 + cost[i - 1], dp0 + cost[i - 2]);
            dp0 = dp1;
            dp1 = dp2;
        }
        return dp1;
    }
};
  • 时间复杂度O(n)
  • 空间复杂度O(1)

你可能感兴趣的:(代码随想录刷题,算法,leetcode,动态规划)