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之和最大即可