心路历程:
这道题可以暴力求解,但是O ( n 2 ) (n^2) (n2)的时间复杂度会超时;也可以用贪心法去做,可以用O ( n ) (n) (n)的时间复杂度去解决。
不过这道题是一个经典的动态规划方法,动态规划方法的重点在于建模,递归函数的参数就是DP的状态,递推函数就是 s i − 1 → s i s_{i-1} \rightarrow s_i si−1→si的可能状态转移过程。
这道题的状态应该定义为:第 i i i天以及第 i i i天是否持有资金,这个很难想到;
动作的定义分为三类,分别是买入、卖出、什么也不做;
返回值定义为第 i i i天的收益。如果第k天买入(k < i),并且第 i i i天还没有卖出去,那么收益就是-prices[i]。
注意的点:
1、贪婪解法需要在每一步维护前i个元素的最小值
2、DP方法的初始化需要区分第0天是不是持有资金
解法一:动态规划
python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
@cache
def dp(i, j): # 第i天,持有j \in {0, 1}股票,最大利润
if i == 0 and j == 0:
return 0
if i == 0 and j == 1: # 这个初始状态的定义比较不好想
return -prices[0]
# 注意只能买卖一次
if j == 0:
return max(dp(i-1, 0), dp(i-1, 1) + prices[i])
else:
return max(dp(i-1, 1), - prices[i])
return dp(len(prices) - 1, 0)
解法二:贪心法
python
class Solution:
def maxProfit(self, prices: List[int]) -> int:
low, res = float('inf'), 0
for i in range(len(prices)):
low = min(low, prices[i])
res = max(res, prices[i] - low)
return res