509. 斐波那契数
题目链接:509. 斐波那契数 - 力扣(LeetCode)
文章链接:代码随想录 (programmercarl.com)
视频链接: 手把手带你入门动态规划 | leetcode:509.斐波那契数
接下来,我将初识动态规划,这道题是动态规划中的简单题。
首先,什么是动态规划?
动态规划中每一个状态一定是由上一个状态推导出来的 。就比如这道题,我想求F(3)就要知道F(2)和F(1),想知道F(2)又要知道F(1)和F(0)。我们通过遍历,逐层状态推导到当前状态的过程,就是动态规划。
用 动态规划五部曲解决该问题:
(1)确定dp数组和下标的含义。
这道题我们需要用dp数组来储存每一层状态产生的值,dp[i]就代表了下标i的斐波那契数列的值,也就是i+1个斐波那契数列的值。
vector<int> dp(n+1)
(2)确认递推公式。
这道题简单就在于题目已经给出了递归公式。
dp[i]=dp[i-1]+dp[i-2]
(3)dp数组初始化。
所有状态产生的值都是由第一层状态的初始值而产生的,所以需要对第一层状态的值初始化。
而斐波那契数列中,第一层状态是dp[0]和dp[1]。
dp[0]=0;//dp数组初始化
dp[1]=1;
(4)确定遍历顺序。
我们想知道某一层状态产生的值,就一定要知道它的前个状态产生的值,想知道dp[i]就要知道dp[i-1]和dp[i-2],所以这道题肯定是从前往后遍历。
for(int i=2;i<=n;i++)
(5)举例推导dp数组
就是举例子带进我推导出的递推数组中,看看是否符合。
总代码如下:
class Solution {
public:
int fib(int n) {
if(n<=1) return n;
vector<int> dp(n+1);//确认dp数组以及下标的含义
dp[0]=0;//dp数组初始化
dp[1]=1;
for(int i=2;i<=n;i++)//确认递归顺序
{
dp[i]=dp[i-1]+dp[i-2];//确认递归公式
}
return dp[n];
}
};
● 70. 爬楼梯
文章链接:代码随想录 (programmercarl.com)
视频链接: 带你学透动态规划-爬楼梯|LeetCode:70.爬楼梯)
这道题,依旧可以用动态规划解决。
动规五部曲:
(1)确定dp数组以及下标的含义
这边的dp数组是用来记录爬n阶楼梯的方法个数,dp[i]代表爬第i阶楼梯的方法个数。
vector<int> dp(n+1)
(2)确定递推公式。
我一开始想的是,由于我一步可以走一阶或者两阶,所以如果想知道i阶楼梯的方法个数dp[i],就需要知道dp[i-1]和dp[i-2],dp[i-2]想到dp[i],可以走两步1阶,也可以一步2阶,所以我就误推成
dp[i]=dp[i-1]+dp[i-2]*2
但是检验时发生了错误,后来又想了想,发现了问题。
我想的“dp[i-2]想到dp[i],可以走两步1阶,也可以一步2阶”,但如果在i-2阶先走一步1阶,就到了i-1阶,所以我想的这种情况其实包含在了dp[i-1]中。
正确递推公式为:
dp[i]=dp[i-1]+dp[i-2];
(3)dp数组初始化。
想知道i阶楼梯的方法个数dp[i],就需要知道dp[i-1]和dp[i-2],dp[i-2],所以我们需要最初始的状态,dp[1]和dp[2].
dp[1]=1;
dp[2]=2;
(4)确认遍历顺序。
肯定是从前往后遍历,常识了......
(5)举例推导dp数组
这道题其实就是斐波那契数列套了个外壳
总代码如下:
class Solution {
public:
int climbStairs(int n) {
if(n<=1) return n;
vector<int> dp(n+1);
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++)
{
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
};
746. 使用最小花费爬楼梯
题目链接:746. 使用最小花费爬楼梯 - 力扣(LeetCode)
文章链接:代码随想录 (programmercarl.com)
视频链接: 动态规划开更了!| LeetCode:746. 使用最小花费爬楼梯
动态五部曲
(1)确定dp数组和下标含义
我们用dp数组来记录到每一层台阶的花费,那么dp[i]就是爬到第i层台阶需要的花费。
vector<int> dp(n+1);
(2)确定递推公式
想到第i层有两种方法,从第i-2层直接跨2阶或者从第i-1层跨1阶,由于我们需要求最低花费,所以我们应该找两者中花费少的那个。
dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
(3)dp数组初始化
题目中说了
你可以选择从下标为 0
或下标为 1
的台阶开始爬楼梯。
这就意味着第0阶和第1阶都可以是我的初识点,当然不需要花费
dp[0]=0;
dp[1]=0;
(4)确认遍历顺序
也很明显,爬楼梯的题一般都是从前往后遍历。
(5)举例推导dp数组
总代码如下:
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n=cost.size();
vector<int> dp(n+1);
dp[0]=0;
dp[1]=0;
for(int i=2;i<n;i++)
{
dp[i]=min(dp[i-1]+cost[i-1],dp[i-2]+cost[i-2]);
}
return min(dp[n-1]+cost[n-1],dp[n-2]+cost[n-2]);
}
};
Day38打卡成功,初识动态规划,我发现动态规划只要按照动规五部曲,思路还是很清晰的,递推的思路是关键点。再接再厉吧!