|
| 1 | +# [3573. 买卖股票的最佳时机 V](https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-v/description/) |
| 2 | + |
| 3 | +> **日期**:2025-02-06 |
| 4 | +> **所用时间**:10min |
| 5 | +> **知识点**:动态规划、记忆化搜索 |
| 6 | +
|
| 7 | +## 1. 题目描述 |
| 8 | + |
| 9 | +给定一个整数数组 `prices`,其中 `prices[i]` 表示第 `i` 天的股票价格,以及一个整数 `k`。要求计算能够获得的最大利润。 |
| 10 | + |
| 11 | +**限制条件:** |
| 12 | + |
| 13 | +- 最多可以完成 **k 笔** 交易(一笔交易指一次买入 + 一次卖出)。 |
| 14 | +- 不能同时参与多笔交易:再次买入前必须先卖出当前持有的股票。 |
| 15 | +- 本题在「买卖股票的最佳时机 IV」的基础上,对**状态**有额外约定(如是否处于持仓、是否处于某类后续状态等),需用多维度状态表示。 |
| 16 | + |
| 17 | +**示例 1:** |
| 18 | + |
| 19 | +- **输入**:prices = [2,4,1], k = 2 |
| 20 | +- **输出**:2 |
| 21 | +- **解释**:第 1 天买入(价格 2),第 2 天卖出(价格 4),利润 2。 |
| 22 | + |
| 23 | +**示例 2:** |
| 24 | + |
| 25 | +- **输入**:prices = [3,2,6,5,0,3], k = 2 |
| 26 | +- **输出**:7 |
| 27 | +- **解释**:第 2 天买入(价格 2),第 3 天卖出(价格 6),利润 4;第 5 天买入(价格 0),第 6 天卖出(价格 3),利润 3。总利润 7。 |
| 28 | + |
| 29 | +**约束:** |
| 30 | + |
| 31 | +- $1 \le k \le 100$ |
| 32 | +- $1 \le \text{prices.length} \le 1000$ |
| 33 | +- $0 \le \text{prices}[i] \le 1000$ |
| 34 | + |
| 35 | +--- |
| 36 | + |
| 37 | +## 2. 记忆化搜索 |
| 38 | + |
| 39 | +**思路:** |
| 40 | + |
| 41 | +在「188. 买卖股票的最佳时机 IV」的「最多 k 笔交易」基础上,用**三态**表示当前所处阶段:`(buy, seil)` 两个布尔量组合出「空仓」「持仓」「另一状态」(如与卖出后的阶段相关)。用**记忆化搜索**:`dfs(i, j, buy, seil)` 表示考虑前 `i+1` 天、剩余 `j` 笔交易、当前处于 `(buy, seil)` 状态时的最大利润。 |
| 42 | + |
| 43 | +- **边界**:`j == 0` 时不能再交易,返回 0;`i < 0` 时若仍持仓或处于 seil 状态为非法(返回 $-\infty$),否则返回 0。 |
| 44 | +- **转移**: |
| 45 | + - 若 `buy == True`:可继续持仓,或在当前天「买入」并消耗一次交易(`dfs(i-1, j-1, False, False) - prices[i]`)。 |
| 46 | + - 若 `seil == True`:可保持当前状态,或在当前天「卖出」并消耗一次交易(`dfs(i-1, j-1, False, False) + prices[i]`)。 |
| 47 | + - 若两者均为 False(空仓):可继续空仓,或从「持仓」转移过来并卖出(+prices[i]),或从「另一状态」转移过来并买入(-prices[i])。 |
| 48 | + |
| 49 | +答案为 `dfs(len(prices)-1, k, False, False)`,即从最后一天、剩余 k 笔、空仓出发的最大利润。 |
| 50 | + |
| 51 | +**复杂度分析:** |
| 52 | + |
| 53 | +- 时间复杂度:$O(n \cdot k)$(状态数 $O(n \cdot k \cdot 4)$,每状态 $O(1)$ 转移) |
| 54 | +- 空间复杂度:$O(n \cdot k)$(递归栈与 cache) |
| 55 | + |
| 56 | +**Python3** |
| 57 | + |
| 58 | +```python |
| 59 | +class Solution: |
| 60 | + def maximumProfit(self, prices: List[int], k: int) -> int: |
| 61 | + @cache |
| 62 | + def dfs(i, j, buy, seil): |
| 63 | + if j == 0: |
| 64 | + return 0 |
| 65 | + if i < 0: |
| 66 | + return -inf if buy or seil else 0 |
| 67 | + if buy: |
| 68 | + return max(dfs(i - 1, j, True, False), dfs(i - 1, j - 1, False, False) - prices[i]) |
| 69 | + if seil: |
| 70 | + return max(dfs(i - 1, j, False, True), dfs(i - 1, j - 1, False, False) + prices[i]) |
| 71 | + return max(dfs(i - 1, j, False, False), dfs(i - 1, j, True, False) + prices[i], dfs(i - 1, j, False, True) - prices[i]) |
| 72 | + ans = dfs(len(prices) - 1, k, False, False) |
| 73 | + dfs.cache_clear() |
| 74 | + return ans |
| 75 | +``` |
0 commit comments