11# 714. 买卖股票的最佳时机含手续费
22
3- > ** 作者:** 弘树
4- > ** 日期:** 2024-09-14
3+ > ** 日期** :2024-09-14
4+ > ** 所用时间** :15min
5+ > ** 知识点** :动态规划、状态机
56
6- ## 解题思路
7- ### 1.动态规划
7+ ## 1. 题目描述
88
9- 状态表示:
9+ 给定一个整数数组 ` prices ` ,其中 ` prices[i] ` 表示第 ` i ` 天的股票价格,以及一个非负整数 ` fee ` 表示 ** 每笔交易的手续费 ** 。可以 ** 无限次 ** 完成交易,求最大利润。
1010
11- 1 . $f[ i] [ 0 ] $表示在第$i$天进行完操作不持有股票的最大利润
12- 2 . $f[ i] [ 1 ] $表示在第$i$天进行完操作持有股票的最大利润
11+ ** 约束条件:**
1312
14- 状态计算:
13+ - 不能同时参与多笔交易:再次买入前必须先卖出之前的股票。
14+ - ** 每笔交易** (一次买入 + 一次卖出)需要支付一次手续费 ` fee ` 。手续费可在** 买入时** 或** 卖出时** 扣除,两种约定等价(只需统一即可)。
15+
16+ ** 示例 1:**
17+
18+ - ** 输入** :prices = [ 1, 3, 2, 8, 4, 9] , fee = 2
19+ - ** 输出** :8
20+ - ** 解释** :第 1 天买入(价格 1),第 4 天卖出(价格 8),利润 8-1-2=5;第 5 天买入(价格 4),第 6 天卖出(价格 9),利润 9-4-2=3。总利润 5+3=8。
21+
22+ ** 示例 2:**
23+
24+ - ** 输入** :prices = [ 1,3,7,5,10,3] , fee = 3
25+ - ** 输出** :6
1526
16- 1 . 若第$i$不持有股票,则有2种可能:
27+ ** 约束: **
1728
18- - 第$i - 1$就没有股票,则$f[ i] [ 0 ] = f[ i - 1] [ 0 ] $
19- - 第$i - 1$持有股票,在第$i$天出售,则$f[ i] [ 0 ] = f[ i - 1] [ 1 ] + prices[ i] - fee$
20-
21- 对于$f[ i] [ 0 ] $的状态转移方程如下:
29+ - $1 \le \text{prices.length} \le 5 \times 10^4$
30+ - $1 \le \text{prices}[ i] < 5 \times 10^4$
31+ - $0 \le \text{fee} < 5 \times 10^4$
2232
23- $$
24- f[i][0] = max(f[i - 1][0], f[i - 1][1] + prices[i] - fee)
25- $$
33+ ---
2634
27- 2 . 若第$i$持有股票,则有2种可能:
35+ ## 2. 动态规划
2836
29- - 第$i - 1$就持有股票,则$f[ i] [ 1 ] = f[ i - 1] [ 1 ] $
30- - 第$i - 1$持不持有股票,在第$i$天购买,则$f[ i] [ 1 ] = f[ i - 1] [ 0 ] - prices[ i] $
37+ ** 思路:**
3138
32- 对于$f [ i ] [ 1 ] $的状态转移方程如下 :
39+ 与「122. 买卖股票的最佳时机 II」类似,无限次交易;区别在于每笔交易要扣手续费。用两态即可 :
3340
34- $$
35- f[i][1] = max(f[i - 1][1], f[i - 1][0] - prices[i])
36- $$
41+ - ** $f[ i] [ 0 ] $** :第 $i$ 天结束时** 不持股** 的最大利润。
42+ - ** $f[ i] [ 1 ] $** :第 $i$ 天结束时** 持股** 的最大利润。
3743
38- 最后答案为$\max(f[ i] [ 0 ] , f[ i] [ 1 ] )$。
44+ ** 转移:**
45+
46+ - 不持股:昨天就不持股,或昨天持股、今天卖出(若在卖出时扣费,则 $f[ i] [ 0 ] = \max(f[ i-1] [ 0 ] , f[ i-1] [ 1 ] + \text{prices}[ i-1] - \text{fee})$)。
47+ - 持股:昨天就持股,或昨天不持股、今天买入(若在买入时扣费,则 $f[ i] [ 1 ] = \max(f[ i-1] [ 1 ] , f[ i-1] [ 0 ] - \text{prices}[ i-1] - \text{fee})$)。
48+
49+ 两种扣费方式任选一种统一即可。答案取 $\max(f[ n] [ 0 ] , f[ n] [ 1 ] )$,实际为 $f[ n] [ 0 ] $(最后不持股更优)。
50+
51+ ** 复杂度分析:**
3952
4053- 时间复杂度:$O(n)$
41- - 空间复杂度:$O(n)$
54+ - 空间复杂度:$O(n)$(DP 数组);可滚动为两个变量,空间 $O(1)$
55+
56+ ** 记忆化搜索(Python)**
57+
58+ ``` python
59+ class Solution :
60+ def maxProfit (self , prices : List[int ], fee : int ) -> int :
61+ @cache
62+ def dfs (i , hold ):
63+ if i < 0 :
64+ return - inf if hold else 0
65+ if hold:
66+ return max (dfs(i - 1 , hold), dfs(i - 1 , False ) - prices[i] - fee)
67+ return max (dfs(i - 1 , hold), dfs(i - 1 , True ) + prices[i])
68+ return dfs(len (prices) - 1 , False )
69+ ```
70+
71+ ** 动态规划(C++)**
72+
73+ 状态表示:
74+
75+ 1 . $f[ i] [ 0 ] $:第 $i$ 天进行完操作不持有股票的最大利润
76+ 2 . $f[ i] [ 1 ] $:第 $i$ 天进行完操作持有股票的最大利润
77+
78+ 状态计算:
79+
80+ - $f[ i] [ 0 ] = \max(f[ i-1] [ 0 ] , f[ i-1] [ 1 ] + \text{prices}[ i-1] - \text{fee})$
81+ - $f[ i] [ 1 ] = \max(f[ i-1] [ 1 ] , f[ i-1] [ 0 ] - \text{prices}[ i-1] )$
82+
83+ 答案为 $\max(f[ n] [ 0 ] , f[ n] [ 1 ] )$。
84+
85+ - 时间复杂度:$O(n)$
86+ - 空间复杂度:$O(n)$
87+
88+ ** C++**
4289
4390``` C++
4491class Solution {
@@ -58,12 +105,14 @@ public:
58105};
59106```
60107
61- ### 2. 滚动数组空间优化
108+ ** 滚动数组空间优化(C++) **
62109
63- 可以看到第 $i$天的状态只依赖于第$i - 1$天,所以可以使用滚动数组的思想 。
110+ 第 $i$ 天只依赖第 $i-1$ 天,可用两个变量滚动 。
64111
65- - 时间复杂度:$O(n)$
66- - 空间复杂度:$O(1)$
112+ - 时间复杂度:$O(n)$
113+ - 空间复杂度:$O(1)$
114+
115+ ** C++**
67116
68117``` C++
69118class Solution {
0 commit comments