https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/description/
public int maxProfit(int[] prices)
{
if(prices.length==0)
{
return 0;
}
int left[]=new int[prices.length];
int right[]=new int[prices.length];
left[0]=0;
right[prices.length-1]=0;
int leftmin=prices[0];//记录左边的最小值
for(int i=1;i<prices.length;i++)
{
if(prices[i]>prices[i-1])
{
left[i]=Math.max(prices[i]-leftmin, left[i-1]);
}
else
{
left[i]=left[i-1];
leftmin=Math.min(leftmin, prices[i]);
}
}
//右
right[prices.length-1]=0;
int rightmax=prices[prices.length-1];//记录右边最大值
for(int i=prices.length-2;i>=0;i--)
{
if(prices[i+1]>prices[i])
{
right[i]=Math.max(rightmax-prices[i], right[i+1]);
}
else
{
right[i]=right[i+1];
rightmax=Math.max(prices[i], rightmax);
}
}
int res=0;
for(int i=0;i<prices.length-1;i++)
{
if(left[i]+right[i]>res)
{
res=left[i]+right[i];
}
}
return res;
}
思路:
与该系列前两题不同 本题要求最多进行“两次”交易
利用动态规划处理
首先最多进行两次交易 可以将prices分为两部分 左边代表一次交易 右边代表第二次交易 而分割的位置是不确定的
但无论分割的位置是哪一处 左边、右边都将成为唯一的 那么只需要计算在每一种分割的情况下 左、右收益之和最大的是哪一种分割就可以了
用题目给出的[3,3,5,0,0,3,1,4]这组数据来还原一下计算步骤
用数组left[]表示左边的“最大收益”
用数组right[]表示右边的“最大收益”
用leftmin表示“目前左边的最低价格” 用rightmax表示“目前右边的最高价格” 为什么这样下面会解释
从left数组的计算开始
对于题目中的 3,3,5,0,0,3,1,4
将leftmin设初值为3 表示第一天买入
之后对题目数据进行遍历
从第二天开始(第一天无论是否买入,都不能卖出,所以没有收益,这时候同时设定left[0]为0)
第二天的价格为3,这个价格并没有高于上一天 (即第一天)的价格
那么此时left[1] 即第二天的最大收益也为0
然后对比第二天的价格与leftmin 相同 那么leftmin保持不变 为3
之后第三天
第三天时价格为5,高于上一天(即第二天)的价格3,若卖出 则收益2 将收益2与之前的最大收益left[1]对比 大于left[1]的0
所以将left[2]设置为2
这里解释一下:此时假定的日期分割为前三天进行第一次交易 后面进行第二次交易
而前三天中的收益分别为0 0 2 意味着 若分割在第一天 则不能买入卖出 收益为0 若分割在第二天 价格为3 3 收益仍为0 分割在第三天 则就是刚才的计算结果 所以left[i]表示的是前i天可以获得的最大收入
接下来继续推进日期
第四天时价格为0 收益仍保持前三天的最大值2 但是此时价格0低于目前的“最低价格” 故将最低价格改为0
第五天不变 略过
第六天时价格为3 此时由于最低价格为0 那么最大收益变为3
按照这样的推理方式结束时
对应日期价格 3,3,5,0,0,3,1,4的
左边最大收益 0,0,2,2,2,3,3,3
用同样的思维方式对右边进行推理 来获得right[]数组 不过由于方式是从右往左
所以需要略作修改 因为从左往右时的默认顺序是买入-卖出 而从右往左是先卖出再买入
这也就是为什么leftmin表示“目前左边的最低价格” 用rightmax表示“目前右边的最高价格”
结束时right数组为4,4,4,4,4,3,3,0
left为: 0,0,2,2,2,3,3,3
之后只需要看哪一组left和right之和最大即可