第九章 动态规划 Part 08
股票问题是一个动态规划的系列问题,前两题并不难,第三题有一定难度。
121. 买卖股票的最佳时机
视频讲解
代码讲解
贪心和暴力算法,之前用过,这次试试动态规划。
dp[i][0] 表示第i天持有股票所得最多现金 ,这里可能有同学疑惑,本题中只能买卖一次,持有股票之后哪还有现金呢?
其实一开始现金是0,那么加入第i天买入股票现金就是 -prices[i], 这是一个负数。
持有股票,要么维持前一天持有股票状态,要么买入更便宜的股票 dp[i][0] = max(dp[i - 1][0], -prices[i]);
dp[i][1] 表示第i天不持有股票所得最多现金。 dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);要么昨天卖,要么今天卖
所以整体思路还是比较好理解的。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
if (len == 0) return 0;
vector<vector<int>> dp(len, vector<int>(2));
dp[0][0] -= prices[0];
dp[0][1] = 0;
for (int i = 1; i < len; i++) {
dp[i][0] = max(dp[i - 1][0], -prices[i]);
dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
}
return dp[len - 1][1];
}
};
dp[i]只是依赖于dp[i - 1]的状态。
这里只开辟了一个2 * 2大小的二维数组,相当于,一直在每两个两个dp[][]进行裁剪,跟流水线一样。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
vector<vector<int>> dp(2, vector<int>(2));
dp[0][0] -= prices[0];
dp[0][1] = 0;
for (int i = 1; i < len; i++) {
dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]);
dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
}
return dp[(len - 1) % 2][1];
}
};
但是也确实更容易出bug
122. 买卖股票的最佳时机 II
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
vector<vector<int>> dp(len, vector<int>(2));
dp[0][0] -= prices[0];
dp[0][1] = 0;
for (int i = 1; i < len; i++) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
}
return dp[len - 1 ][1];
}
};
买入股票的时候,可能会有之前买卖的利润即:dp[i - 1][1],所以dp[i - 1][1] - prices[i]。通过dp[i][0]将之前的链接起来。
123. 买卖股票的最佳时机 III
这道题一下子就难度上来了,关键在于至多买卖两次,这意味着可以买卖一次,也可以买卖两次,还可以不买卖。
没有操作 (其实我们也可以不设置这个状态)确实,因为没有操作,手上的现金自然就是0
第一次持有股票
第一次不持有股票
第二次持有股票
第二次不持有股票
其实就是,买入,卖出,再买入,再卖出。
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() == 0) return 0;
vector<vector<int>> dp(prices.size(), vector<int>(5, 0));
dp[0][1] = -prices[0];
dp[0][3] = -prices[0];
for (int i = 1; i < prices.size(); i++) {
dp[i][1] = max(dp[i - 1][1], 0 - prices[i]);
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}
return dp[prices.size() - 1][4];
}
};
好家伙,纯纯又加了两列,再做一次。其实看懂代码,这题并不难。