时隔将近20天没有刷题,这20天在找实习中,迷茫了思绪。打断了自己的节奏。甚至基本没干什么。每天陷在自我纠结、内耗中。失意、摆烂、振作、乱。循环往复。反正是这20天基本没学什么东西。之后不能这样了,不能被任何事情打断自己的节奏,必须每天保证完成自己的刷题任务、求职知识学习任务、课题导师任务也要让老师满意。在此立个flag:不荒废每天的时间,直到找到心仪的工作。学习时候不能总想看b站、被其他事情打断自己的节奏。
所幸结果不算太坏,算是求上得中了吧。至少导师能放我一小段时间就是胜利。真心感谢我的导师。还有帮助我的师兄。在此就不说名字了。
在这期间面试了一些中小公司,也了解了一些东西。希望在之后的日子里抓紧冲。毕竟算法岗卷到爆炸,想进去使用全部力气甚至不容易,更何况不用力气呢?千万不能在水了!!!!
下面开始继续刷题!
第九章 动态规划part01
理论基础
五步走:
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
509. 斐波那契数
比较简单,用来熟悉动规五步走
需要注意的就是:定义dp数组
vector<int> dp(N + 1);
定义dp数组时,能初始化完整就初始化完整,比如大小和初始化的值。这里因为要求dp(n),从0开始,所以大小为n+1.
第二个需要注意的就是改进的方法。
class Solution {
public:
int fib(int N) {
if (N <= 1) return N;
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];
}
};
- 时间复杂度:O(n):一个for循环。
- 空间复杂度:O(n):开辟了一个大小为n+1的数组。
可以对其进行改进,因为dp(n)只与他的前两个值相关,因此可以只维护前两个值。将空间复杂度降低到O(1).
class Solution {
public:
int fib(int N) {
if (N <= 1) 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):for循环
- 空间复杂度:O(1):只维护dp[0]和dp[1]。循环使用。记住此时定义dp数组时,初始大小是2就可以了。不要多定义。
70. 爬楼梯
和上面那道题一样
n个楼梯时的方法就是n-1个楼梯爬一步和n-2个楼梯爬两步,懂这个就可以了。
class Solution {
public:
int climbStairs(int n) {
if (n <= 1) return n; // 因为下面直接对dp[2]操作了,防止空指针
vector<int> dp(n + 1);
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) { // 注意i是从3开始的
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
};
746. 使用最小花费爬楼梯
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
vector<int> dp(cost.size() + 1);
dp[0] = 0; // 默认第一步都是不花费体力的
dp[1] = 0;
for (int i = 2; i <= cost.size(); i++) {
dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]);
}
return dp[cost.size()];
}
};
这个需要注意dp数组大小,是提供的数组的大小+1,因为索引从0开始。