这一篇总结leetcode里关于股票的题目,都是用dynamic programming
- Best Time to Buy and Sell Stock
https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/
只能操作一次
class Solution {
public:
int maxProfit(vector<int>& prices) {
int maxp = 0;
int minbuy = INT_MAX;
for(int i = 0; i < prices.size(); i++)
{
minbuy = min(minbuy , prices[i]);
maxp = max(maxp , prices[i] - minbuy );
}
return maxp ;
}
};
- Best Time to Buy and Sell Stock II
https://leetcode.com/problems/best-time-to-buy-and-sell-stock/description/
可以操作多次
这个题最优解很简单,但不是那么容易捋清楚,
主要考虑两种模式:
一:a < b < c < d (monotone increase)
res = d - a = b - a + c - b + d - c
二:a < b > c < d (non monotone increase)
res = b - a + d - c (必定> d - a)
所以结果就是 if (prices[i+1] > prices[i]) res =+ prices[i+1] - prices[i];
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0;
for(int i = 0; i+1 < prices.size(); i++)
{
res += max(0, prices[i+1] - prices[i]);
}
return res;
}
};
- Best Time to Buy and Sell Stock III
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/description/
允许最多两次操作
这个写法也很精简,但是想法并不简单,或者说并不容易想清楚,这个解法是从leetcode discuss上来的(meng789987)
我理解的大概的思想:每次交易都试图找minbuy price,同时试图找maxprofit price就像只允许交易一次那样,since允许两次交易,第二次交易,需要把第一次交易的maxprofit包含进去,那么第二次交易的maxprofit就是最后打答案。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int maxp1 = 0, maxp2 = 0;
int minbuy1 = INT_MAX, minbuy2 = INT_MAX;
for(int i = 0; i < prices.size(); i++)
{
minbuy1 = min(minbuy1, prices[i]);
maxp1 = max(maxp1, prices[i] - minbuy1);
minbuy2 = min(minbuy2, prices[i] - maxp1);
maxp2 = max(maxp2, prices[i] - minbuy2);
}
return maxp2;
}
};
- Best Time to Buy and Sell Stock IV
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/description/
允许最多k次
这个解法是上面的延申,但是k = 1000000000 时会有std::bad_alloc
可能space不够优化?
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
if(prices.size() < 1) return 0;
vector<int>minbuy(k+1, prices[0]);
vector<int>maxp(k+1, 0);
for(int i = 1; i < prices.size(); i++)
{
for(int j = 1; j <= k; j++)
{
minbuy[j] = min(minbuy[j], prices[i] - maxp[j-1]);
maxp[j] = max(maxp[j], prices[i] - minbuy[j]);
}
}
return maxp[k];
}
};
309 Best Time to Buy and Sell Stock with Cooldown
After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Note: cooldown only happens after sell.
这个题是个非常典型的dynamic programming。
dynamic programming的关键是找transition function.
buy[i]是记录如果i day买入股票的最大的profit (所以,buy[0]=-prices[0])
sell[i]是记录如果i day卖掉股票的最大的profit (所以,sell[0]=0)
buy[i] = max(buy[i-1], sell[i-2] - prices[i])
sell[i] = max(sell[i-1], buy[i-1]+prices[i])
iday只有三种操作,卖或者买或者什么也不做
对于buy[i], 如果iday不买,如果iday买,找出最大。
不买,就是buy[i-1];
买就是sell[i-2]-prices[i], 因为有cooldown,所以必须是前两天的sell
对于sell[i], 如果iday不卖,如果iday卖,找出最大。
不卖,就是sell[i-1];
卖就是buy[i-1]+prices[i],卖和买之间并没有cooldown
int maxProfit(vector<int>& prices) {
int size = prices.size();
if(size < 1) return 0;
vector<int>buy(size);
vector<int>sell(size);
buy[0] = -prices[0];
sell[0] = 0;
for(int i = 1; i < size; i++)
{
buy[i] = max(buy[i-1], (i >= 2 ? sell[i-2] : 0) - prices[i]);
sell[i] = max(sell[i-1], buy[i-1] + prices[i]);
}
return sell[size - 1];
}
};
这个空间复杂度是O(n),
但是buy or sell只跟前面的买和卖有关,可以继续优化
int prebuy = - prices[0];
int presell = 0, prepresell = 0;
int buy = 0, sell = 0;
for(int i = 1; i < size; i++)
{
int tmp = presell;
buy = max(prebuy, (i >= 2 ? prepresell : 0) - prices[i]);
sell = max(presell, prebuy + prices[i]);
prebuy = buy;
prepresell = tmp;
presell = sell;
}
return sell;