1.初步了解动态规划
由于本篇博客属于动态规划的初阶学习,所以大多都是简单的表示,更深层次的学术用语会在之后深度学习动态规划之后出现,本文主要是带各位了解一下动态规划的大致框架
1.1状态表示
通常的我们会开辟一个dp数组来存储需要表示的数据,其中dp[i]代指我们需要表示的位置,那么dp[i]的数据状态就是题目给出的限制条件,比如泰波那契数列中的第i个值或者最小花费爬楼梯的第i个台阶
1.2状态转移方程
通常的我们表示dp[i]位置的数据需要一定的公式,这种公式就是状态转移方程,比如泰波那契数列的第i个数是第i-3,i-2,i-1三个数之和,那么dp[i] = dp[i-3]+dp[i-2]+dp[i-1]就是泰波那契数列的状态转移方程,总的来说状态转移方程就是我们表示某一个特定位置需要遵循的规律
1.3初始化
一般来说在dp表中的前几个位置都是题目给出的,需要初始化用来表示后面的数据,这里依旧使用泰波那契数列举例,泰波那契数列的一开始三个位置的值分别为0、1、1,我们要用这三个值迭代求出第i(i>=4)个位置的值,那么初始化就要初始化dp表的前三个位置
1.4填表顺序
一般来说填表都是逐个填表,不能跳跃某个位置,比如已知泰波那契数列的前三个位置的值就可以在第四个位置填表,但是如果在第五个位置填表就会出错,并且需要注意防止填表时越界,需要对边界情况特殊处理
1.5返回值
通常题目都会给出要求返回某个位置的值,比如给定某个变量n,求出第n个位置的值即可,需要具体题目具体讨论
2.实战代码练习
2.1题目解析
题目来源: 1137.第N个泰波那契数——力扣
测试用例
题目来源:746.最小花费爬楼梯——力扣
最小花费爬楼梯——牛客
测试用例
2.2算法原理
第N个泰波那契数
泰波那契数:目标位置前三个位置的和等于目标位置的值,前三个数为0/1/1
1.创建dp表,第n个泰波那契数就是dp表的第n+1个值,但是下标还是n
2.初始化前三个值
3.使用状态转移方程求出第n个泰波那契数
第N个泰波那契数——优化版本
当需要求第i个位置的值就只需要保存i-1/i-2/i-3这三个位置的值即可,那么其他位置就会浪费,所以这里我们使用动态数组进行优化,即
1.只创建三个变量a/b/c作为滚动数组,使用d来存储第i个泰波那契数
2.不断将三个变量向后移动直到求出第n个泰波那契数,返回d即可
最小花费爬楼梯
已知需要爬到楼顶,而楼顶代表的是数组末尾数字的下一个位置,即n+1个位置,所以创建一个dp表返回到dp[n]位置的最小花费即可
1.因为每次只能走两步,所以第i个位置的最小花费就是第i-1与第i-2两个位置的较小值,那么我们就得到了状态转移方程dp[i]=min(cost[i-1]+dp[i-1],cost[i-2]+dp[i-2])
2.最终填表完成后直接返回dp[n]就代表第n+1个位置的值也就是到楼顶的最小花费
2.3代码展示
第N个泰波那契数
class Solution {
public:
int tribonacci(int n)
{
//创建dp表
vector<int> dp(n + 1);
//初始化
dp[0] = 0;
dp[1] = dp[2] = 1;
//处理边界情况
if(n == 0)
{
return 0;
}
if(n == 1 || n == 2)
{
return 1;
}
//状态表示方程
for(int i = 3;i <= n;i++)
{
dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
}
return dp[n];
}
};
第N个泰波那契数——优化版本
class Solution {
public:
int tribonacci(int n)
{
int a = 0,b = 1, c = 1;
int d = 0;
if(n == 0)
{
return 0;
}
if(n == 1 || n == 2)
{
return 1;
}
//滚动数组
for(int i = 3;i <= n;i++)
{
d = a + b + c;
a = b;
b = c;
c = d;
}
return d;
}
};
最小花费爬楼梯
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost)
{
int n = cost.size();
//创建dp表
vector<int> dp(n + 1);
//初始化
dp[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];
}
};