问题描述:在T+1交易规则下,给出每天股票的买/卖价序列,要求在序列期间内最多只允许买、卖各一次,求此期间内的最大收益是多少(可以选择不卖,即收益为0)
比如:
(1)价格序列为[7,1,5,3,6,4],则最大收益为5,即选择第2天买入(买入价1)、第5天卖出(卖出价6)
(2)价格序列为[7,6,4,3,1],则最大收益率为0,即只能选择买入,但因为价格持续下降,所以无法卖出。
方案一:显然可以暴力求解,两层循环求出各买入/卖出可能下的收益情况,求出最大值即可
def MaxStockGain(prices:list):
gains = []
for i in range(0, len(prices)-1):
for j in range(i+1, len(prices)):
gains.append(prices[j] - prices[i])
max_gain = max(gains)
return max(max_gain, 0)
print(MaxStockGain([7, 1, 5, 3, 6, 4])) # 5
print(MaxStockGain([7, 6, 4, 3, 1])) # 0
上述暴力法的计算复杂度为 O ( n 2 ) O(n^2) O(n2),那能否更简单的求解该问题呢?
方案二:线性扫描一遍列表,假设在位置 L ( i ) L(i) L(i)处卖出,则其买入点必然为前序列表处价格最低点处,而决定该点卖出是否划算只需对比此时卖出收益和前序卖出各方案的max值。
由此,引入两个状态量:
a
[
i
]
a[i]
a[i]:从序列开始到
L
(
i
)
L(i)
L(i)的最低价格(作为买入点)
b
b
b:从序列开始到
L
(
i
)
L(i)
L(i)的最大收益值
状态迭代函数为:
a
[
i
+
1
]
=
min
{
a
[
i
]
,
L
[
i
+
1
]
}
a[i+1]=\min\{a[i], L[i+1]\}
a[i+1]=min{a[i],L[i+1]}
b
=
max
{
b
,
L
[
i
+
1
]
−
a
[
i
+
1
]
}
b=\max\{b, L[i+1]-a[i+1]\}
b=max{b,L[i+1]−a[i+1]}
初始条件为:
a
[
1
]
=
L
[
1
]
a[1]=L[1]
a[1]=L[1],
b
[
1
]
=
0
b[1]=0
b[1]=0
据此,相应代码为:
def MaxStockGain(prices:list):
min_price = prices[0] # 记录到第i天时,所有天数里股票价格最大值,即买入点。初始值为第一天
max_gain = 0 # 记录到第i天时,卖出的最大收益。初始值第一天买入后,一致持有的收益
for p in prices[1:]:
min_price = min(min_price, p)
max_gain = max(max_gain, p - min_price)
return max_gain
print(MaxStockGain([7, 1, 5, 3, 6, 4])) # 5
print(MaxStockGain([7, 6, 4, 3, 1])) # 0