动态规划day32|动态规划理论基础、509. 斐波那契数(动规梦的开始)、70. 爬楼梯、746. 使用最小花费爬楼梯(dp[i]该怎么定义?)

动态规划day32|动态规划理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

动态规划理论基础

  • 动态规划,英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。

  • 动规是由前一个状态推导出来的,而贪心是局部直接选最优的

  • 动态规划五步曲:

    • 确定dp数组(dp table)以及下标的含义

    • 确定递推公式

    • dp数组如何初始化

    • 确定遍历顺序

    • 举例推导dp数组

509. 斐波那契数

斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 01 开始,后面的每一项数字都是前面两项数字的和。也就是:

F(0) = 0,F(1) = 1
F(n) = F(n - 1) + F(n - 2),其中 n > 1

给定 n ,请计算 F(n)

示例 1:

输入:n = 2
输出:1
解释:F(2) = F(1) + F(0) = 1 + 0 = 1

示例 2:

输入:n = 3
输出:2
解释:F(3) = F(2) + F(1) = 1 + 1 = 2

示例 3:

输入:n = 4
输出:3
解释:F(4) = F(3) + F(2) = 2 + 1 = 3

提示:

  • 0 <= n <= 30
class Solution {
public:
    int fib(int n) {
        if(n<=1)
        return n;
        vector<int> dp(n+1);
        dp[0]=0,dp[1]=1;
        for(int i=2;i<dp.size();i++)
        {
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
};

本题比较简单,但是要代入五部曲思考一下。

70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶

示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

提示:

  • 1 <= n <= 45
class Solution {
public:
    int climbStairs(int n) {
        if(n<=2)
        return n;
       vector<int> dp(n+1);
        dp[1]=1,dp[2]=2;
        for(int i=3;i<dp.size();i++)
        {
            dp[i]=dp[i-1]+dp[i-2];
        }
        return dp[n];
    }
};

这题跟509比较像,递归公式是:dp[i]=dp[i-1]+dp[i-2],其他的地方都比较简单。

dp[i]=dp[i-1]+dp[i-2]是怎么得来的?答:我认为,dp[i]的情况有两个部分组成,一是dp[i-1]的情况加1得来,二是dp[i-2]的情况加2的来。(我承认我有赌的成分,感觉理论上可以,没有去验证,结果就通过了)

746. 使用最小花费爬楼梯

给你一个整数数组 cost ,其中 cost[i] 是从楼梯第 i 个台阶向上爬需要支付的费用。一旦你支付此费用,即可选择向上爬一个或者两个台阶。

你可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯。

请你计算并返回达到楼梯顶部的最低花费。

示例 1:

输入:cost = [10,15,20]
输出:15
解释:你将从下标为 1 的台阶开始。
- 支付 15 ,向上爬两个台阶,到达楼梯顶部。
总花费为 15 。

示例 2:

输入:cost = [1,100,1,1,1,100,1,1,100,1]
输出:6
解释:你将从下标为 0 的台阶开始。
- 支付 1 ,向上爬两个台阶,到达下标为 2 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 4 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 6 的台阶。
- 支付 1 ,向上爬一个台阶,到达下标为 7 的台阶。
- 支付 1 ,向上爬两个台阶,到达下标为 9 的台阶。
- 支付 1 ,向上爬一个台阶,到达楼梯顶部。
总花费为 6 。

提示:

  • 2 <= cost.length <= 1000
  • 0 <= cost[i] <= 999
class Solution {
public:
    int minCostClimbingStairs(vector<int>& cost) {
        if(cost.size()<=2)
        return min(cost[0],cost[1]);
        vector<int> 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()];
    }
};

本题的关键是怎么去定义dp[i],正确的定义法是:dp[i]是到达第i级台阶时总的花费,需要注意的是,我们这里设置的是开区间即不包括第i级(因为到楼顶时是不包括楼顶的,这样一以贯之)

因此,递推公式就出来了:

dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);

所以我们要学会用函数,如min、max,因为这样可以省写不少代码(偷懒),这道题也是整体性的思维,是用整体的逻辑去写for循环的,而不是仅仅看着这一层for循环。

小总结:dp[i]的定义往往是关键的中间量或者直接是result的前状态们。70是前者,509和746都是后者。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值