代码随想录算法训练营第三十二天| 122 买卖股票的最佳时机II 55 跳跃游戏 45 跳跃游戏II
LeetCode 122 买卖股票的最佳时机II
题目链接: 122.买卖股票的最佳时机II
思路:只有一支股票,只有买股票和卖股票的操作。
可以将利润分解成以每天为单位的维度,而不是从某一天再到另一天去考虑!
然后利用贪心算法只收集正的利润,通过收集每天的正利润来实现全局最优。
//版本一
class Solution {
public:
int maxProfit(vector<int>& prices) {
int result = 0;
for(int i = 1; i < prices.size(); i++) {
result += max(prices[i] - prices[i - 1], 0);
}
return result;
}
};
动态规划(虽然不懂,但是尝试理解理解)
class Solution {
public:
int maxProfit(vector<int>& prices) {
//dp[i][1]第i天持有的最多现金
//dp[i][0]第i天持有股票后的最多现金
int n = prices.size();
vector<vector<int> > dp(n, vector<int>(2, 0));
dp[0][0] -= prices[0]; //持股票
for(int i = 1; i < n; i++) {
//第i天持股票所剩最多现金 = max(第i-1天持股票所剩现金-买第i天的股票)
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
//第i天持股票持有最多现金 = max(第i - 1天持有的最多现金,第i - 1天持有股票的最多现金+第i天卖出股票)
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
}
return max(dp[n - 1][0], dp[n - 1][1]);
}
};
股票问题实质上是一个系列,属于动态规划的范畴。
LeetCode 55 跳跃游戏
题目链接: 55.跳跃游戏
思路:刚接触到本题时会想到究竟跳几步,思考会比较多,但是我们应该思考可跳的覆盖范围,不一定非要明确一次究竟调几步,每次取最大步数,明确覆盖范围即可。那么此问题转变为跳跃覆盖范围究竟能否覆盖到终点。
局部最优:每次取最大值
整体最优:最后得到整体覆盖范围,看能否到达终点
i每次移动只能在cover的范围内移动,每移动一个元素,cover得到该元素数量数值,然后i继续移动下去。
cover每次只取max,若cover能够覆盖终点下标,return true即可。
class Solution {
public:
bool canJump(vector<int>& nums) {
int cover = 0;
if(nums.size() == 1) return true;
for(int i = 0; i <= cover; i++) {
cover = max(i + nums[i], cover);
if(cover >= nums.size() - 1) return true;
}
return false;
}
};
LeetCode 45 跳跃游戏II
题目链接: 45.跳跃游戏II
思路:此题比上题要复杂很多,虽然按照贪心的思想,局部最优就是尽可能先多走,,从而实现整体最优。然而从代码里无法体现能走多远就走多远。
所以此题需要统计两个覆盖范:当前这一步的最大覆盖范围和下一步最大覆盖范围。
若当前移动下标到达了当前这一步的最大覆盖距离还没到终点,就必须再走一步来增加覆盖范围,直到覆盖范围覆盖终点。
class Solution{
public:
int jump(vector<int>& nums) {
if(nums.size() == 1) return 0;
int curDistance = 0; //当前覆盖最远距离下标
int ans = 0;
int nextDistance = 0; //下一步覆盖最远距离下标
for(int i = 0; i < nums.size(); i++) {
nextDistance = max(nums[i] + i, nextDistance);
if(i == curDistance) {
if(curDistance < nums.size() - 1) {
ans++;
curDistance = nextDistance;
if(nextDistance >= nums.size() - 1) break;
} else break;
}
}
return ans;
}
};
// 版本二
class Solution {
public:
int jump(vector<int>& nums) {
int curDistance = 0; // 当前覆盖的最远距离下标
int ans = 0; // 记录走的最大步数
int nextDistance = 0; // 下一步覆盖的最远距离下标
for (int i = 0; i < nums.size() - 1; i++) { // 注意这里是小于nums.size() - 1,这是关键所在
nextDistance = max(nums[i] + i, nextDistance); // 更新下一步覆盖的最远距离下标
if (i == curDistance) { // 遇到当前覆盖的最远距离下标
curDistance = nextDistance; // 更新当前覆盖的最远距离下标
ans++;
}
}
return ans;
}
};
总结:看起来很简单,但是想不到