代码随想录算法训练营第二十八天任务
- 动态规划理论基础
- [509. 斐波那契数](#509. 斐波那契数)
- [70. 爬楼梯](#70. 爬楼梯)
- [746. 使用最小花费爬楼梯](#746. 使用最小花费爬楼梯)
动态规划理论基础
动态规划(Dynamic Programming,DP)每一个状态是由上一个状态推导出来的。
如果某一个问题有很多重叠子问题,使用动态规划是最有效的。
动态规划解题五步曲:
- 确定dp数组以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
这5步缺一不可,心法在这里代码随想录-动态规划理论基础
509. 斐波那契数
分析:
- 确定dp数组以及下标的含义
dp[i]:第i项斐波那契数 - 确定递推公式
dp[i] = dp[i-1] + dp[i-2] - dp数组如何初始化
dp[0] = 0, dp[1] = 1, i > 1, dp[i] = ... - 确定遍历顺序
0->n - 举例推导dp数组
dp[2] = dp[1] + dp[0] = 1 + 0 = 1
dp[3] = dp[2] + dp[1] = 1 + 1 = 2
dp[4] = dp[3] + dp[2] = 2 + 1 = 3
cpp
class Solution {
public:
int fib(int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fib(n-1) + fib(n-2);
}
};
时间复杂度:O(2n)
空间复杂度:O(n)
另解:
cpp
class Solution {
public:
int fib(int n) {
if (n < 2) return n;
int dp[2];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; ++i) {
int sum = dp[0] + dp[1];
dp[0] = dp[1];
dp[1] = sum;
}
return dp[1];
}
};
时间复杂度:O(n)
空间复杂度:O(1) 固定大小的数组
70. 爬楼梯
分析:
- 确定dp数组以及下标的含义
dp[i]:到达 第 i 阶有 dp[i] 种方法 - 确定递推公式
dp[i] = dp[i-1] + dp[i-2] - dp数组如何初始化
dp[1] = 1, dp[2] = 2 - 确定遍历顺序
0-->n - 举例推导dp数组
dp[3] = dp[2] + dp[1] = 3
dp[4] = dp[3] + dp[2] = 5
n = 4时,- 1 阶 + 1 阶 + 1 阶 + 1 阶
- 1 阶 + 2 阶 + 1 阶
- 2 阶 + 1 阶 + 1 阶
- 1 阶 + 1 阶 + 2 阶
- 2 阶 + 2 阶
cpp
class Solution {
public:
int climbStairs(int n) {
if (n < 3) return n;
int dp[2];
dp[0] = 1;
dp[1] = 2;
for (int i = 3; i <= n; ++i) {
int sum = dp[0] + dp[1];
dp[0] = dp[1];
dp[1] = sum;
}
return dp[1];
}
};
时间复杂度:O(n)
空间复杂度:O(1) 固定大小的数组
746. 使用最小花费爬楼梯
分析:
-
确定dp数组以及下标的含义
dp[i]:到达 第 i 个台阶需要支付的最低费用为dp[i]
-
确定递推公式
dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
-
dp数组如何初始化
dp[0] = 0, dp[1] = 0 可以选择从下标为 0 或下标为 1 的台阶开始爬楼梯,说明到达 第 0 或者 1的台阶的费用为0
-
确定遍历顺序
0-->n
-
举例推导dp数组
eg: cost = [10,15,20]
dp[2] = min(dp[1] + cost[1], dp[0] + cost[0]) = 10
dp[3] = min(dp[2] + cost[2], dp[1] + cost[1]) = min(30, 15) = 15
eg: cost = cost = [1,100,1,1,1,100,1,1,100,1]
dp[2] = min(dp[1] + cost[1], dp[0] + cost[0]) = 1
dp[3] = min(dp[2] + cost[2], dp[1] + cost[1]) = min(2, 100) = 2
dp[4] = min(dp[3] + cost[3], dp[2] + cost[2]) = min(3, 2) = 2
dp[5] = min(dp[4] + cost[4], dp[3] + cost[3]) = min(2+1, 2+1) = 3
dp[6] = min(dp[5] + cost[5], dp[4] + cost[4]) = min(3+100, 2+1) = 3
dp[7] = min(dp[6] + cost[6], dp[5] + cost[5]) = min(3+1, 3+100) = 4
dp[8] = min(dp[7] + cost[7], dp[6] + cost[6]) = min(4+1, 3+1) = 4
dp[9] = min(dp[8] + cost[8], dp[7] + cost[7]) = min(4+100, 4+1) = 5
dp[10] = min(dp[9] + cost[9], dp[8] + cost[8]) = min(5+1, 4+100) = 6
cpp
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
if(cost.size() < 2) return 0;
int dp[2];
dp[0] = 0;
dp[1] = 0;
for(int i = 2; i <= cost.size(); ++i) {
int lowcost = min(dp[1] + cost[i-1], dp[0] + cost[i-2]);
dp[0] = dp[1];
dp[1] = lowcost;
}
return dp[1];
}
};
时间复杂度:O(n)
空间复杂度:O(1) 固定大小的数组
五步曲太好用了!!!
复习支线开启💪