Leetcode里的买卖股票系列非常有名。之前做过这个系列里面的三道,分别是:
121 Best Time to Buy and Sell Stock
其中第一道题的要求是只能交易一次,因此就是寻找数组内正向的最大差值,解法是维护一个min变量存储当前遇到的最低股价,维护一个max存储当前可能的最大利润(用当前股价减去min),一次顺序遍历数组最后返回max就ok了。代码:
int maxProfit(vector& prices) {
int size=prices.size(), res=0, minPrice=INT_MAX;
for(int i=0;i
122 Best Time to Buy and Sell Stock II
第二道题要求是可以进行多次交易,利用贪心就可以了,每次股价比昨天贵就加上这个差值。代码:
int maxProfit(vector& prices) {
int total = 0;
for (int i=0; i<(int)prices.size()-1; i++) {
if (prices[i+1]>prices[i])
total += prices[i+1]-prices[i];
}
return total;
}
123 Best Time to Buy and Sell Stock III
前两道都是Easy题,第三道开始变成Hard。题目要求是可以进行两次交易,需要使用动态规划。我们维护两种量,一个是当前到达第i天可以最多进行j次交易,最好的利润是多少(global[i][j]),另一个是当前到达第i天,最多可进行j次交易,并且最后一次交易在当天卖出的最好的利润是多少(local[i][j])。两个数组的递推公式如下:
local[i+1][j+1]=max(local[i][j+1]+diff,global[i][j]+max(diff,0))
global[i+1][j+1]=max(global[i][j+1],local[i+1][j+1])
具体的分析可以参考这个帖子。代码:
int maxProfit(vector& prices) {
if(prices.size()==0)
return 0;
int local[3] = {0};
int global[3] = {0};
//say there are 5 days, i iterates to 3(not 4). After every iteration of i, global[] return the profit up to (i+1)th days.
for(int i=0;i=1;j--)
{
local[j] = max(global[j-1]+(diff>0?diff:0), local[j]+diff);
global[j] = max(local[j],global[j]);
}
}
return global[2];
}
另外还看到网上有一种利用状态机的解法,状态机的思路在股票系列的另一道中也有应用(LC 309. Best Time to Buy and Sell Stock with Cooldown),关于这道题可以参考我的另外一篇帖子。利用状态机用到了四个状态,分别为:
Buy1[i]表示前i天做第一笔交易买入股票后剩下的最多的钱;
Sell1[i]表示前i天做第一笔交易卖出股票后剩下的最多的钱;
Buy2[i]表示前i天做第二笔交易买入股票后剩下的最多的钱;
Sell2[i]表示前i天做第二笔交易卖出股票后剩下的最多的钱;
int maxProfit(vector& prices) {
int buy1 = INT_MIN;
int buy2 = INT_MIN;
int sell1 = 0;
int sell2 = 0;
for(int i = 0; i < prices.size(); i++)
{
sell2 = max(sell2, buy2+prices[i]);
buy2 = max(buy2, sell1-prices[i]);
sell1 = max(sell1, buy1+prices[i]);
buy1 = max(buy1,-prices[i]);
}
return sell2;
}
解释一下循环里的代码。例如
sell2 = max(sell2, buy2+prices[i]);
当前状态之前的某个状态已经经历了buy2,考虑这个时候sell2可能从什么状态转化而来。其中可能是昨天买入的,即昨天经历了buy2,因此今天的sell2如果把昨天买入的股票售出的话,总金额就变变为buy2+prices[i] (buy2表示经历过buy2状态之后的金钱的总数)。当然不论是昨天还是过去的哪一天经历的buy2,如果在当前的这一天卖出的话,金钱总数sell2总是buy2+prices[i]。另外一种可能是今天不卖,那么今天结束的时候金额的总数就和昨天相同,所以就是sell2. 在另外一道股票系列题目LC309中给出了状态机的示意图,虽然题目的背景有所不同但是相信看了之后会帮助理解这里讲的状态机变化的过程。