121.买卖股票的最佳时机
思路描述
对于上述的描述而言,我们有两种思路:
- 找到下一个时间点与当前时间点的差值,只考虑将最大的股票价格减去最小的股票价格
- 使用
DP
的方式进行动态规划转移
由于我本人对于DP
较为感兴趣,所以我们使用第二种方法来解题,解题的思路如下: - step1.先定义动态转移方程,我们可以设第
i
i
i 天的最大利润是
max profit
,而这个最大利润我们简记为MP
,那么MP
的动态转移方程就与前一天的动态转移方程有关,所以 M P [ i ] = M P [ i − 1 ] + i s b u y o r n o t MP[i]=MP[i-1]+isbuyornot MP[i]=MP[i−1]+isbuyornot 这里的 i s b u y o r n o t isbuyornot isbuyornot 非常麻烦,所以在MP
坐标轴上引入多一维的空间表达,这个空间表达为 M P [ i ] [ j ] MP[i][j] MP[i][j] ,那么 M P [ i ] [ j ] MP[i][j] MP[i][j] 中的 j j j 代表着三种状态:- 0:不动
- 1:买入
- 2:卖出
设 a [ i ] a[i] a[i] 是我们的 l i s t list list列表,那么动态转移方程从原来的第 i i i天金额的变换为第 i − 1 i-1 i−1天加上股票的买卖,公式定义如下:
M P [ i ] = { M P [ i ] = M P [ i − 1 ] + ( − a [ i ] ) M P [ i ] = M P [ i − 1 ] + a [ i ] MP[i]=\left\{ \begin{aligned} MP[i] & = & MP[i-1] + (-a[i]) \\ MP[i] & = & MP[i-1] + a[i] \end{aligned} \right. MP[i]={MP[i]MP[i]==MP[i−1]+(−a[i])MP[i−1]+a[i]
转换为第 i i i天中手上是否持有股票, 0 0 0代表无, 1 1 1代表有:
M P [ i , 0 ] = { M P [ i , 0 ] = M P [ i − 1 , 1 ] + a [ i ] M P [ i , 0 ] = M P [ i − 1 , 0 ] MP[i, 0]=\left\{ \begin{aligned} MP[i,0] & = & MP[i-1,1] + a[i] \\ MP[i,0] & = & MP[i-1, 0] \end{aligned} \right. MP[i,0]={MP[i,0]MP[i,0]==MP[i−1,1]+a[i]MP[i−1,0]
M P [ i , 1 ] = { M P [ i , 1 ] = M P [ i − 1 , 0 ] + ( − a [ i ] ) M P [ i , 1 ] = M P [ i − 1 , 1 ] MP[i, 1]=\left\{ \begin{aligned} MP[i,1] & = & MP[i-1,0] + (-a[i]) \\ MP[i,1] & = & MP[i-1, 1] \end{aligned} \right. MP[i,1]={MP[i,1]MP[i,1]==MP[i−1,0]+(−a[i])MP[i−1,1]
总体表达后,就可以使用矩阵来代表动态转移方程的变换,行代表第 i i i 步操作(与已知的股票序列长度有关),列代表第 i i i步执行操作后所得到的状态,由于只计算一次,那么找到其中的最大值即可:
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices: return 0
res = 0
profit = [[0 for i in range(3)] for i in range(len(prices))]
profit[0][0], profit[0][1], profit[0][2] = 0, -prices[0], 0
for i in range(1, len(prices)):
profit[i][0] = 0
profit[i][1] = max(profit[i-1][1], profit[i-1][0] - prices[i])
profit[i][2] = profit[i-1][1] + prices[i]
res = max(res,profit[i][0], profit[i][1], profit[i][2])
return res
查看执行效率:
对于Python
而言,这可不是一个很光彩的执行效率,所以尽量的使用第一种思想来操作:
123.买卖股票的最佳时机 III
题目描述:
这里可以增加多一个维度,这个维度是买卖了多少次,也就是说,由原来的
M
P
[
i
]
[
j
]
MP[i][j]
MP[i][j] 变换成
M
P
[
i
]
[
j
]
[
k
]
MP[i][j][k]
MP[i][j][k],其中
k
k
k 代表了买卖了多少次,方程也可以表达为
M
P
[
i
]
[
k
]
[
j
]
MP[i][k][j]
MP[i][k][j]:
M
P
[
i
,
k
,
0
]
=
{
M
P
[
i
,
k
,
0
]
=
M
P
[
i
−
1
,
k
,
0
]
M
P
[
i
,
k
,
0
]
=
M
P
[
i
−
1
,
k
−
1
,
1
]
+
a
[
i
]
MP[i, k, 0]=\left\{ \begin{aligned} MP[i, k, 0] & = & MP[i-1, k, 0] \\ MP[i, k, 0] & = & MP[i-1, k-1, 1] + a[i] \end{aligned} \right.
MP[i,k,0]={MP[i,k,0]MP[i,k,0]==MP[i−1,k,0]MP[i−1,k−1,1]+a[i]
M
P
[
i
,
k
,
1
]
=
{
M
P
[
i
,
k
,
1
]
=
M
P
[
i
−
1
,
k
,
1
]
M
P
[
i
,
k
,
1
]
=
M
P
[
i
−
1
,
k
−
1
,
0
]
−
a
[
i
]
MP[i, k, 1]=\left\{ \begin{aligned} MP[i, k, 1] & = & MP[i-1, k, 1] \\ MP[i, k, 1] & = & MP[i-1, k-1, 0] - a[i] \end{aligned} \right.
MP[i,k,1]={MP[i,k,1]MP[i,k,1]==MP[i−1,k,1]MP[i−1,k−1,0]−a[i]
最后状态:
max
M
P
[
n
,
0
,
.
.
.
,
k
,
0
]
\max{MP[n, {0,...,k}, 0]}
maxMP[n,0,...,k,0]
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices: return 0
profit = [[[0 for _ in range(2)] for _ in range(3)] for _ in range(len(prices))]
profit[0][0][0], profit[0][0][1] = 0, -prices[0]
profit[0][1][0], profit[0][1][1] = -sys.maxsize, -sys.maxsize
profit[0][2][0], profit[0][2][1] = -sys.maxsize, -sys.maxsize
for i in range(1, len(prices)):
profit[i][0][0] = profit[i-1][0][0]
profit[i][0][1] = max(profit[i-1][0][1], profit[i-1][0][0] - prices[i])
profit[i][1][0] = max(profit[i-1][1][0], profit[i-1][0][1] + prices[i])
profit[i][1][1] = max(profit[i-1][1][1], profit[i-1][1][0] - prices[i])
profit[i][2][0] = max(profit[i-1][2][0], profit[i-1][1][1] + prices[i])
end = len(prices) - 1
return max(profit[end][0][0], profit[end][1][0], profit[end][2][0])