【状态机DP】LeetCode 123. 买卖股票的最佳时机|||
前言
状态机 DP是一种特殊的动态规划方法,它将问题建模为一个状态机(有限状态自动机),然后在这个状态机上进行状态转移。
状态机三要素
- 状态划分(互斥状态)
- 转移规则(状态机图)
- 资源约束(次数限制)
题目
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
题解
第一步,进行状态划分,找到互斥的状态:
总共有 \(n\) 天,可以完成两笔交易,每天至多操作一次(买入/卖出)。因此可以定义出以下五种状态:
- 未进行过任何交易(没有操作也是一种操作)
- 执行了第一笔交易的买入
- 在已经执行了第一笔交易的买入的基础上,执行第一笔交易的卖出
- 在已经执行了第一笔交易的卖出的基础上,执行第二笔交易的买入
- 在已经执行了第二笔交易的买入的基础上,执行第二笔交易的卖出
第二步,制定转移规则,设计状态机图:

第三步,明确资源约束条件
该题的资源约束条件是限制交易次数为至多两次,也就是任意一次操作必须符合第一步定义的五种状态之一。
定义 \(dp[i][j]\) 为在前 \(i\) 天状态为第 \(j\) 种状态。
由状态机图,可列出以下状态转移方程:
dp[i + 1][0] = max(dp[i][0], -prices[i]);
dp[i + 1][1] = max(dp[i][1], prices[i] + dp[i][0]);
dp[i + 1][2] = max(dp[i][2], -prices[i] + dp[i][1]);
dp[i + 1][3] = max(dp[i][3], prices[i] + dp[i][2]);
参考代码
朴素 DP 版本
时间复杂度:\(O(n)\)
空间复杂度:\(O(4 \times n)\)
constexpr int INF = -1e9;
int dp[100001][4] = {INF, INF, INF, INF};
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
for (int i = 0; i < n; ++ i) {
dp[i + 1][0] = max(dp[i][0], -prices[i]);
dp[i + 1][1] = max(dp[i][1], prices[i] + dp[i][0]);
dp[i + 1][2] = max(dp[i][2], -prices[i] + dp[i][1]);
dp[i + 1][3] = max(dp[i][3], prices[i] + dp[i][2]);
}
return max(0, *max_element(dp[n], dp[n] + 4));
}
};
空间优化版本
时间复杂度:\(O(n)\)
空间复杂度:\(O(1)\)
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
int buy1 = -1e9, buy2 = -1e9;
int sell1 = 0, sell2 = 0;
for (int i = 0; i < n; ++ i) {
sell1 = max(sell1, prices[i] + buy1);
buy1 = max(buy1, -prices[i]);
sell2 = max(sell2, prices[i] + buy2);
buy2 = max(buy2, sell1 - prices[i]);
}
return sell2;
}
};
浙公网安备 33010602011771号