一、动态规划基础知识点(参考)
动态规划五步骤:
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
动态规划的题目分类:
1 基础题目
2 背包问题
3 打家劫舍
4 股票问题
5 子序列问题
注意:动态规划题目,一定要理解dp的含义,以及状态转移公式的推导。
二、509 斐波那契数列
此题目动态规划的转移方程题目已经列出来,根据动态规划的步骤,进行分析:
1 dp[i]代表F[i],初始值F[0] = 0 F[1] = 1;
2 状态转移方程:F(n) = F(n-1) + F(n -2)
3 最后返回F(n)
int fib(int n){
//第一步 初始化值
int dp[2];
dp[0] = 0;
dp[1] = 1;
if(n <= 1)
{
return n;
}
//step2: 确定状态转移,题目已经给了F(n) = F(n - 1) + F(n - 2)
for(int i = 2; i <= n; i++)
{
int sum = dp[0] + dp[1];//sum在此时是fn,
dp[0] = dp[1];//向前进一个
dp[1] = sum;//用dp1取代fn
}
return dp[1];
}
三、70 爬楼梯
题目规定可以走1步或者2步,需要 n 阶你才能到达楼顶,有多少方案?
1 dp[i]代表走到i阶梯上的方案数量,初始化时候,0阶梯讨论无意义,dp[1] =1 dp[2] =2
2 转移方程dp[i] = dp[i -1] + dp[i-2]
3 输出dp[n]
int climbStairs(int n) {
if(n <= 1)
{
return n;
}
//申请dp 代码的爬楼梯的方案数量
int* dp = (int*)calloc(n + 1, sizeof(int));
//初始化 1个阶梯只有1个方法,2个阶梯可以跳1步(2次),可以跳2步一次,有2个方案
dp[1] = 1;
dp[2] = 2;
//状态转移 + 遍历顺序 i 依赖于i -1 and i - 2
for(int i = 3; i <= n; i++)
{
dp[i] = dp[i - 1] + dp[i - 2];
}
//返回值,第n个楼梯的方案
return dp[n];
}
四、746. 使用最小花费爬楼梯
题目给出了cost数组,并且说明了0 1阶梯不会有花费,因此初始化dp可以设置0,dp[i]代表i层阶梯的最小花费,状态转移为:
dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
直到转移到dp[costsize]
int minCostClimbingStairs(int* cost, int costSize) {
int* dp = (int*)malloc(sizeof(int) * (1 + costSize));
//dp代表体力花费 0 1阶梯不花费
dp[0] = 0;
dp[1] = 0;
for(int i = 2; i <= costSize; i++)
{
dp[i] = dp[i - 1] + cost[i - 1] > dp[i - 2] + cost[i - 2]?
dp[i -2] + cost[i - 2] : dp[i - 1] + cost[i -1];
}
return dp[costSize];
}