Day38——动态规划Ⅰ
- 1.理论
- #2.leetcode_509斐波那契数
- 3.leetcode_70爬楼梯
- 4.kamacoder_57爬楼梯
- 5.leetcode_746使用最小花费爬楼梯
1.理论
一般解题步骤:
- 确定dp数组及下标含义
- 确定递推公式
- 数组如何初始化
- 确定递归顺序
- 举例推导dp数组
#2.leetcode_509斐波那契数
思路:1. 递归
2. 动态规划的方式考虑5个问题:
1. dp数组及下标的含义: 第i个数的斐波那契数值是dp[i]
2. 递推公式:f[i] = f[i-1] + f[i-2];
3. 数组如何初始化:因为递推公式用到了i-1 i-2,因此初始化0,1位置
4. 确定递归顺序:
5. 举例推导递推公式 dp[i] = dp[i-1] + dp[i-2];
int fib(int n) {if(n < 2) return n;vector<int> dp(n+1); // 第n个数的斐波那契数列值是dp[n],因此最少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];}
优化下:
int fib(int n) {if(n < 2) return n;int dp[2] = {0};dp[0] = 0;dp[1] = 1;for(int i = 2; i <= n; i++) {dp[1] = dp[1] + dp[0];dp[0] = dp[1] - dp[0];}return dp[1];}
3.leetcode_70爬楼梯
思路:熟悉一下动态规划5步:
1. 确定动态规划数组及下标含义:爬 i 阶的楼梯共有 dp[i] 种爬法, i > 0
2. 确定递推公式: f(i) = f(i-2) + 2; 每次可以爬1~2个,这里每次只有两种爬法,1+1 / 2
3. 数组如何初始化:至少需要知道 i-2 > 0 的爬法有多少种, 初始化 dp[0], dp[1];
4. 确定递推顺序:从前向后
5. 举例推导 dp 数组: dp[i] = dp[i-2] + 2; (i >= 2)
写了一下,答案错误,感觉模拟的没问题,应该是递推公式有误,虽然只有两种爬法,但没有考虑如果是3,既可以先爬一步再爬两步,也可以先爬两步再爬一步。。确定递推公式时,如果爬两个一步,那不就是 i - 1的爬法吗,如果爬两步那就是i - 2的爬法,所以应该是 f(i) = f(i-1) + f(i-2);
int climbStairs(int n) {int dp[2];dp[0] = 1;dp[1] = 1;for(int i = 2; i <= n; i++) {dp[1] += dp[0];dp[0] = dp[1] - dp[0];}return dp[1];}
4.kamacoder_57爬楼梯
思路:
- 确定动态规划数组及下标含义:爬 n 阶楼梯共有 dp[n] 种方法
- 确定递推公式:f(n) = f(n-1) + f(n-2) + … + f(n-m)
- 数组如何初始化: dp[0] = 1
- 确定顺序:从前向后
- 举例推导 dp 数组: dp[i] = dp[i-1] + … + dp[i-m];
#include <iostream>
#include <vector>using namespace std;int main(){int n, m;cin >> n >> m;vector<int> dp(n + 1, 0);dp[0] = 1;for(int i = 1; i <= n; i++) {for(int j = 1; j <= m; j++) {// cout << i << " " << j << " ";if(i >= j) {dp[i] += dp[i-j];// cout << dp[i] << " " << dp[i-j];}// cout << endl;}}cout << dp[n];return 0;
}
5.leetcode_746使用最小花费爬楼梯
思路:
- 确定动态规划数组及下标含义:从 n 阶楼梯爬到顶最少花费 dp[n]
- 确定递推公式:f(n) = min(f(n-1),f(n-2));
- 数组如何初始化: dp[n] = cost[n], dp[n-1] = cost[n-1];
- 确定顺序:从后向前,从已知到未知
- 举例推导 dp 数组: dp[n] = min(dp[n+1], dp[n+2]) + cost[n];
int minCostClimbingStairs(vector<int>& cost) {int dp[2];int size = cost.size();dp[1] = cost[size - 1];dp[0] = cost[size - 2];for(int i = size - 3; i >= 0; i--) {int tmp = dp[0];dp[0] = min(tmp, dp[1]) + cost[i];dp[1] = tmp;}return min(dp[0], dp[1]);}
题解方法二:
int minCostClimbingStairs(vector<int>& cost) {int dp0 = 0;int dp1 = 0;for (int i = 2; i <= cost.size(); i++) {int dpi = min(dp1 + cost[i - 1], dp0 + cost[i - 2]);dp0 = dp1; // 记录一下前两位dp1 = dpi;}return dp1;}