题目:
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most two transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
思路:
1、O(n)空间复杂度的动态规划:由于最多进行两次交易,所以第一次交易和第二次交易的分割点就比较关键。我们定义left_max[i]表示在[0, i]区间内完成一笔交易所能获得的最利润,而right_max[i]则表示在[i, prices.size() - 1]区间内完成一笔交易所能获得的最大利润。显然,left_max和right_max都可以通过线性扫描,采用贪心策略正确计算出来,最后线性扫描,取得最佳分割点即可。不过,最后别忘了将交易两次的获利和只交易一次的最大获利相比较,并取最大值(left_max[prices.size() - 1]或者right_max[0])。
2、O(1)空间复杂度的动态规划:可以交易两次,因此可以记录一下两次买和两次卖之后的最大利润。因为可以交易两次,所以第二次交易将会依赖于第一次的结果,即第二次买下一个股票剩下的利润依赖于之前第一次卖掉股票之后的利润——当前的股票价格。同理第二次卖掉一支股票之后剩下的利润依赖于第二次买下一支股票之后剩下的利润+当前的股票价格。注意,我们在这里其实也就是把买入一只股票当作了-prices[i]的收益。
代码:
1、O(n)空间复杂度的动态规划:
class Solution {
public:
int maxProfit(vector<int>& prices)
{
if(prices.size() <= 1)
return 0;
vector<int> left_max(prices.size(), 0);
vector<int> right_max(prices.size(), 0);
int lowest_price = prices[0];
for(int i = 1; i < prices.size(); ++i)
{
if(prices[i] < lowest_price)
lowest_price = prices[i];
left_max[i] = max(left_max[i - 1], prices[i] - lowest_price);
}
int highest_price = prices[prices.size() - 1];
for(int i = prices.size() - 2; i >= 0; --i)
{
if(prices[i] > highest_price)
highest_price = prices[i];
right_max[i] = max(right_max[i + 1], highest_price - prices[i]);
}
int max_profit = 0;
for(int i = 0; i < prices.size() - 1; ++i)
{
int sum_price = left_max[i] + right_max[i + 1];
if(max_profit < sum_price)
max_profit = sum_price;
}
return max(max_profit, right_max[0]);
}
};
2、O(1)空间复杂度的动态规划:
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() == 0) {
return 0;
}
int buy1 = INT_MIN, buy2 = INT_MIN, sell1 = 0, sell2 = 0;
for (auto it = prices.begin(); it != prices.end(); ++it) {
buy1 = max(buy1, -*it);
sell1 = max(sell1, buy1 + *it);
buy2 = max(buy2, sell1 - *it);
sell2 = max(sell2, buy2 + *it);
}
return sell2;
}
};