第九章 动态规划part01
1.理论基础
代码随想录
B站卡哥视频
对于动态规划问题,我将拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!
确定dp数组(dp table)以及下标的含义
确定递推公式
dp数组如何初始化
确定遍历顺序
举例推导dp数组
2.LeetCode. 斐波那契数
2.1题目链接:
2.2思路:动规五部曲:
这里我们要用一个一维dp数组来保存递归的结果
确定dp数组以及下标的含义
dp[i]的定义为:第i个数的斐波那契数值是dp[i]
确定递推公式
为什么这是一道非常简单的入门题目呢?
因为题目已经把递推公式直接给我们了:状态转移方程 dp[i] = dp[i - 1] + dp[i - 2];
dp数组如何初始化
题目中把如何初始化也直接给我们了,如下:
dp[0] = 0;
dp[1] = 1;
确定遍历顺序
从递归公式dp[i] = dp[i - 1] + dp[i - 2];中可以看出,dp[i]是依赖 dp[i - 1] 和 dp[i - 2],那么遍历的顺序一定是从前到后遍历的
举例推导dp数组
按照这个递推公式dp[i] = dp[i - 1] + dp[i - 2],我们来推导一下,当N为10的时候,dp数组应该是如下的数列:
0 1 1 2 3 5 8 13 21 34 55
如果代码写出来,发现结果不对,就把dp数组打印出来看看和我们推导的数列是不是一致的。
2.3附加代码如下所示:
//精简版
class Solution {
public:
int fib(int n) {
if(n==0)return 0;
if(n==1)return 1;
int dp[2];
dp[0]=0;
dp[1]=1;
//不断更新dp[0]和dp[1]
for(int i=2;i<=n;i++)
{
int sum=dp[0]+dp[1];
dp[0]=dp[1];
dp[1]=sum;
}
return dp[1];
}
};
class Solution {
public:
int fib(int n) {
if(n==0)return 0;
if(n==1)return 1;
vector<int>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];
}
};
3.LeetCode.爬楼梯
3.1题目链接:
3.2思路:爬到第一层楼梯有一种方法,爬到二层楼梯有两种方法。
那么第一层楼梯再跨两步就到第三层 ,第二层楼梯再跨一步就到第三层。
所以到第三层楼梯的状态可以由第二层楼梯 和 到第一层楼梯状态推导出来,那么就可以想到动态规划了。
3.3附加代码如下所示:
class Solution {
public:
int climbStairs(int n) {
if(n==1)return 1;
if(n==2)return 2;
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];
}
};
//精简版
class Solution {
public:
int climbStairs(int n) {
if(n==1)return 1;
if(n==2)return 2;
int dp[3];//因为这里dp[0]没有意义就不用初始化了
dp[1]=1;
dp[2]=2;
for(int i=3;i<=n;i++)
{
int sum=dp[1]+dp[2];
dp[1]=dp[2];
dp[2]=sum;
}
return dp[2];
}
};
4.LeetCode.使用最小花费爬楼梯
4.1题目链接:
4.2思路:可以有两个途径得到dp[i],一个是dp[i-1] 一个是dp[i-2]。
dp[i - 1] 跳到 dp[i] 需要花费 dp[i - 1] + cost[i - 1]。
dp[i - 2] 跳到 dp[i] 需要花费 dp[i - 2] + cost[i - 2]。
那么究竟是选从dp[i - 1]跳还是从dp[i - 2]跳呢?
一定是选最小的,所以dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
4.3附加代码如下所示:
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n=cost.size();
vector<int>dp(n+1);//开辟n+1哥数组是因为遍历到顶楼时候正好是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 dp[n];
}
};
//版本二
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n=cost.size();
int dp0=0;//默认第一步都是不花费的
int dp1=0;
for(int i=2;i<=n;i++)
{
int result=min(dp0+cost[i-2],dp1+cost[i-1]);
dp0=dp1;
dp1=result;
}
return dp1;
}
};