继续进行买卖股票系列~
LeetCode 123 买卖股票的最佳时机III
题目链接:123. 买卖股票的最佳时机 III - 力扣(Leetcode)
买卖股票的第三个版本同样是在买卖次数上做文章,强调最多能交易两次,也就是买入卖出各两次,同样要求买入前必须保证手里没有持有。如果沿用买卖股票I和II的做法,就无法确定dp推导过程中的交易次数。因此需要重新进行状态定义,状态从股票持有变为交易状态,分别记录每一天如果为第一次买入、第一次卖出、第二次买入、第二次卖出时的最大利润,可以保证买入卖出的先后顺序。
确定状态后,状态推导和初始化就比较容易想到了。第一次买入前没有交易,因此要么延续前一天的状态,要么在当天在利润为0的情况下买入,而第一次卖出必须在第一次买入的基础上进行,其他状态的分析类似。两次买入的初始状态均为在第0天买入花费的prices[0],而卖出可以是在买入的同一天卖出,因此可以初始化为0。因为是最多两次交易,获得最大利润时可能只进行了一次交易,因此返回后一天两次卖出中较大的利润作为最终结果。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int len = prices.size();
int buy1 = -prices[0], sell1 = 0;
int buy2 = -prices[0], sell2 = 0;
for (int i = 1; i < len; ++i) {
buy1 = max(buy1, -prices[i]);
sell1 = max(sell1, buy1 + prices[i]);
buy2 = max(buy2, sell1 - prices[i]);
sell2 = max(sell2, buy2 + prices[i]);
}
return sell2;
}
};
上述代码直接进行了空间复杂度优化,时间和空间复杂度分别是O(n)和O(1)。
LeetCode 188 买卖股票的最佳时机IV
题目链接:188. 买卖股票的最佳时机 IV - 力扣(Leetcode)
这一题和III其实异曲同工,相当于先用两次交易打个底,拓展到k次就比较简单了。最多可以进行k次交易,因此状态有2k个,记录每一天第k次买入或卖出可以获得的最大利润,通过一次内层循环依次更新每个状态即可。买入的状态均初始化为-prices[0],卖出的状态均初始化为0,时间和空间复杂度分别是O(kn)和O(k)。
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
vector<int> buys(k, -prices[0]);
vector<int> sells(k, 0);
for(int i=1; i < n; i++){
for(int j=0; j < k; j++){
if(j==0) buys[j] = max(buys[j], - prices[i]);
else buys[j] = max(buys[j], sells[j-1] - prices[i]);
sells[j] = max(sells[j], buys[j] + prices[i]);
}
}
return sells[k-1];
}
};