代码随想录刷题Day38 | 509.斐波那契数 、70.爬楼梯 、746.使用最小花费爬楼梯

代码随想录刷题Day38 | 509.斐波那契数 、70.爬楼梯 、746.使用最小花费爬楼梯

今日任务

509.斐波那契数

70.爬楼梯

746.使用最小花费爬楼梯

509.斐波那契数

方法很简单,不讲

class Solution {
public:
    int fib(int n) {
        int F[31] = {0};
        F[1] = 1;
        for (int i = 2; i <= n; ++i) F[i] = F[i - 1] + F[i - 2];
        return F[n];
    }
};

或者省空间点的

class Solution {
public:
    int fib(int n) {
        if (!n) return 0;
        int front = 0, rear = 1, tmp;
        for (int i = 2; i <= n; ++i) {
            tmp = rear;
            rear = front + rear;
            front = tmp;
        }
        return rear;
    }
};

注意也可以用递归来做

class Solution {
public:
    int fib(int n) {
        if (n < 2) return n;
        return fib(n - 1) + fib(n - 2);
    }
};
// time: O(n^2)
// space: O(n), 算上了编程语言中实现递归的系统栈所占空间

分析递归的时间复杂度直接画树形图即可,具体见文章:通过一道面试题目,讲一讲递归算法的时间复杂度!

70.爬楼梯

主要思想

  • dp[i] 表示到达第i阶有几种方法
  • 那么到达 第 i 阶分两类方法
    • 可以从第 i - 1 阶跨一步(从 1 阶到 i - 1 阶有 dp[i - 1]种方法)
    • 可以从第 i - 2 阶跨两步(从 1 阶到 i - 2 阶有 dp[i - 2] 种方法)
    • 综上,到 第 i 阶共有 dp[i] = dp[i - 1] + dp[i - 2] 种方法
  • dp[1] = 1, dp[2] = 2

所以代码如下

class Solution {
public:
    int climbStairs(int n) {
        int dp[46] = {0};
        dp[1] = 1, dp[2] = 2;
        for (int i = 3; i <= n; ++i) dp[i] = dp[i - 1] + dp[i - 2];
        return dp[n];
    }
};

省空间版本

class Solution {
public:
    int climbStairs(int n) {
        int dp[3];
        dp[1] = 1;
        dp[2] = 2;
        if (n < 3) return dp[n];
        int sum;
        for (int i = 3; i <= n; ++i) {
            sum = dp[1] + dp[2];
            dp[1] = dp[2];
            dp[2] = sum;
        }
        return sum;
    }
};

拓展

关于本题还可以继续深化,就是一步一个台阶、两个台阶、三个…一直到m个台阶,共有多少种方式爬到n阶

可以看看这道题目377. 组合总和 Ⅳ

746.使用最小花费爬楼梯

主要思想

  • dp[i] 表示从 i 阶走的最少总花费
  • 由于每次可以跨一步或者跨两步,所以:dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]
  • 由于到顶端需要从倒数第二或倒数第一个台阶走,所以返回 min(dp[n - 1], dp[n - 2])
class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int n = cost.size(); // 本题n >= 2
        vector<int> dp(n, 0);
        // dp[i] 表示从i阶走的最少花费
        dp[0] = cost[0];
        dp[1] = cost[1];
        for (int i = 2; i < n; ++i) dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i];
        // 由于到顶端需要从倒数第二或倒数第一个台阶走,所以返回min(dp[n - 1], dp[n - 2]);
        return min(dp[n - 1], dp[n - 2]);
    }
};

省内存版本

class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        int dp0 = cost[0];
        int dp1 = cost[1];
        int tmp;
        for (int i = 2; i < cost.size(); ++i) {
            tmp = min(dp0, dp1) + cost[i];
            dp0 = dp1; // 记录前两位
            dp1 = tmp;
        }
        return min(dp0, dp1);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值