121.买卖股票的最佳时机
最多1笔交易
class Solution {
public int maxProfit(int[] prices) {
// 我们使用一个变量专门记录到[0,i]中的最小值
if(prices.length==0)
return 0;
int minPrice = prices[0];
int profit = 0; //用来记录[0,i]天我们获得的最大利润,我们不希望亏本,所以选择0作为初始值
for(int i=1;i<prices.length;i++){
if(prices[i]<minPrice)
minPrice=prices[i];
profit = Math.max(profit,prices[i]-minPrice);
}
return profit;
}
}
123.买卖股票的最佳时机
- 最多2笔交易。
- 相似题目:
121,122,123
思路一:连续贪心2次(错误)
这里的思路是参考121的思路,我们在第一次贪心完的左右侧在进行贪心。
反例:
[6,1,3,2,4,7]
错误的解答:
(7-1)+0=6
正确答案:
(3-1)+(7-2)=7
class Solution {
// 找到[start,end[间获利最多的办法 -> 121题
// 返回最大利润,startIndex,endIndex 表示第startIndex天买入,第endIndex天卖出
public int[] maxProfit(int[] prices,int start,int end) {
int[] res = new int[3]; //为了便于理解,我们就最后赋值
if(start==end || start<0 || end>prices.length)
return res;
int startIndex=start,endIndex=start,minIndex=start;
int minPrice = prices[start];
int profit = 0; //用来记录[0,i]天我们获得的最大利润,我们不希望亏本,所以选择0作为初始值
for(int i=start+1;i<end;i++){
if(prices[i]<minPrice){
minPrice=prices[i];
minIndex=i; //minPrice记录的是第minIndex天的价格
}
if(profit<prices[i]-minPrice){
profit = prices[i]-minPrice;
startIndex=minIndex;
endIndex = i;
}
}
res[0]=profit;
res[1]=startIndex;
res[2]=endIndex;
return res;
}
public int maxProfit(int[] prices) {
int[] invest1,invest2; //用于记录最后两个投资
int[] investl,investr;
invest1 = maxProfit(prices,0,prices.length);
System.out.println("invest1 "+invest1[0]+" "+invest1[1]+" "+invest1[2]+" ");
investl = maxProfit(prices,0,invest1[1]+1); //如果可以买入又卖出,即第i天先卖再买入
investr = maxProfit(prices,invest1[2],prices.length);
System.out.println("investl "+investl[0]+" "+investl[1]+" "+investl[2]+" ");
System.out.println("investr "+investr[0]+" "+investr[1]+" "+investr[2]+" ");
return invest1[0]+Math.max(investl[0],investr[0]);
}
}
思路二:动态规划
首先,我们给出问题中所有可能的状态:
- 未进行任何操作
- 进行过1次买的操作
- 进行过1次买和卖的操作
- 在完成了一笔交易的基础上,进行了第二次买的操作。
- 完成了2笔买卖
并且我们发现状态 i i i只能到状态 i + 1 i+1 i+1或状态 i i i,不存在跳跃的情况。
接着,我们考虑各个状态所能获得的最大利润,分别记为:
- 0 (因为没有完成任何交易)
- b u y 1 buy_1 buy1
- s e l l 1 sell_1 sell1
- b u y 2 buy_2 buy2
- s e l l 2 sell_2 sell2
然后,我们希望给出每个“时刻”这些变量的值,即状态转移方程
- 状态一:0 ∀ i \forall i ∀i。
- 状态二: b u y 1 [ i ] = m a x ( b u y 1 [ i − 1 ] , − p r i c e [ i ] ) buy_1[i] = max(buy_1[i-1],-price[i]) buy1[i]=max(buy1[i−1],−price[i]),即我们是在[0,i-1]中某一天买,还是第i天买,目的就是在最便宜的时候买进。
- 状态三: s e l l 1 [ i ] = m a x ( s e l l 1 [ i − 1 ] , b u y 1 [ i − 1 ] + p r i c e [ i ] ) sell_1[i]=max(sell_1[i-1],buy_1[i-1]+price[i]) sell1[i]=max(sell1[i−1],buy1[i−1]+price[i]),即我们是在第[i-1]天卖掉,还是第i天卖掉。
- 状态四: b u y 2 [ i ] = m a x ( b u y 2 [ i − 1 ] , s e l l 1 [ i − 1 ] − p r i c e [ i ] ) buy_2[i]=max(buy_2[i-1],sell_1[i-1]-price[i]) buy2[i]=max(buy2[i−1],sell1[i−1]−price[i])
- 状态五: s e l l 2 [ i ] = m a x ( s e l l 2 [ i − 1 ] , s e l l 2 [ i − 1 ] + p r i c e [ i ] ) sell_2[i]=max(sell_2[i-1],sell_2[i-1]+price[i]) sell2[i]=max(sell2[i−1],sell2[i−1]+price[i])
因此我们的状态转移方程为:
{
b
u
y
1
=
m
a
x
{
b
u
y
1
,
−
p
r
i
c
e
s
[
i
]
}
s
e
l
l
1
=
m
a
x
{
s
e
l
l
1
,
b
u
y
1
+
p
r
i
c
e
s
[
i
]
}
b
u
y
2
=
m
a
x
{
s
e
l
l
1
,
s
e
l
l
1
−
p
r
i
c
e
s
[
i
]
}
s
e
l
l
2
=
m
a
x
{
s
e
l
l
2
,
b
u
y
2
+
p
r
i
c
e
s
[
i
]
}
\left\{\begin{matrix} buy_1 = max\{buy_1,-prices[i]\} \\ sell_1 = max\{sell_1,buy_1+prices[i]\} \\ buy_2 = max\{sell_1,sell_1-prices[i]\} \\ sell_2 = max\{sell_2,buy_2+prices[i]\} \end{matrix}\right.
⎩⎪⎪⎨⎪⎪⎧buy1=max{buy1,−prices[i]}sell1=max{sell1,buy1+prices[i]}buy2=max{sell1,sell1−prices[i]}sell2=max{sell2,buy2+prices[i]}
初始条件:
{
b
u
y
1
=
−
p
r
i
c
e
s
[
0
]
s
e
l
l
1
=
0
b
u
y
2
=
−
p
r
i
c
e
s
[
0
]
s
e
l
l
2
=
0
\left\{\begin{matrix} buy_1 = -prices[0] \\ sell_1 = 0 \\ buy_2 = -prices[0] \\ sell_2 = 0 \end{matrix}\right.
⎩⎪⎪⎨⎪⎪⎧buy1=−prices[0]sell1=0buy2=−prices[0]sell2=0
最后看看我们返回哪个值,
鉴于
s
e
l
l
1
,
s
e
l
l
2
sell_1,sell_2
sell1,sell2的初始值就是0了,它们之后的值都一定比0要大,所以我们不用考虑状态1的0了。
此时,我们考虑的就是,到最后返回的到底是1次交易还是2次交易?
实际上,我们可以把1次交易看成2次交易,即在buy1卖出的那天同时进行买卖操作。这样sell2的值就会和sell1重合了。
因此我们只需要返回sell2即可
class Solution {
public int maxProfit(int[] prices) {
if(prices.length==0)
return 0;
int buy1=-prices[0],sell1=0,buy2=-prices[0],sell2=0;
for(int i=0;i<prices.length;i++){
buy1 = Math.max(buy1,-prices[i]);
sell1 = Math.max(sell1,buy1+prices[i]);
buy2 = Math.max(buy2,sell1-prices[i]);
sell2 = Math.max(sell2,buy2+prices[i]);
}
return sell2;
}
}