309. 买卖股票的最佳时机含冷冻期
给定一个整数数组prices
,其中第 prices[i]
表示第 i
天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: prices = [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
示例 2:
输入: prices = [1]
输出: 0
提示:
1 <= prices.length <= 5000
0 <= prices[i] <= 1000
动态规划,数组递推
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length; // 获取价格数组的长度
int[][] dp = new int[n][2]; // 定义动态规划数组
for (int i = 0; i < n; i++) {
// base case 1
// 当 i 为 0 (即第一天) 时的处理
if (i - 1 == -1) {
dp[i][0] = 0; // 第一天不持有股票的利润为0
dp[i][1] = -prices[i]; // 第一天持有股票的利润为 -prices[i]
continue;
}
// base case 2
// 当 i 为 1 (即第二天) 时的处理
if (i - 2 == -1) {
// 第二天不持有股票的最大利润为前一天不持有股票的利润或前一天持有后今天卖出
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
// 第二天持有股票的最大利润为前一天持有股票的利润或前一天不持有今天买入
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
// dp[i][1]
// = max(dp[i-1][1], dp[-1][0] - prices[i])
// = max(dp[i-1][1], 0 - prices[i])
// = max(dp[i-1][1], -prices[i])
continue;
}
// 通常情况下的状态转移方程
// 第 i 天不持有股票的最大利润:保持前一天的不持有状态或者前一天持有今天卖出
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
// 第 i 天持有股票的最大利润:保持前一天的持有状态或者前两天不持有今天买入(卖出后需要冷却一天)。严格来说是max(dp[i-1][1], dp[i-2][0]-prices[i], -prices[i]),其中-prices[i]指前一天没有股票今天再买,不是前一天卖了股票今天再买!但是dp[i-2][0]一定大于0,所以把第三项略去了。
// 由于 i - 2 也可能小于 0,所以上面多了一个 i - 2 < 0 的 base case
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 2][0] - prices[i]);
}
return dp[n - 1][0]; // 返回最后一天不持有股票的最大利润
}
}
时间复杂度O(N),空间复杂度O(N)
动态规划,滚动更新
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
// 初始化滚动变量
int noStockToday = 0; // 表示今天不持有股票的最大利润
int holdStockToday = -prices[0]; // 表示今天持有股票的最大利润
int noStockTwoDaysAgo = 0; // 表示两天前不持有股票的最大利润
for (int i = 1; i < n; i++) {
// 暂存今天不持有股票的利润,用于更新两天前的状态
int noStockYesterday = noStockToday;
// 更新今天不持有股票的最大利润:
// 1. 继续昨天不持有股票的状态
// 2. 或者昨天持有股票,今天卖出
noStockToday = Math.max(noStockToday, holdStockToday + prices[i]);
// 更新今天持有股票的最大利润:
// 1. 继续昨天持有股票的状态
// 2. 或者两天前不持有股票,今天买入
holdStockToday = Math.max(holdStockToday, noStockTwoDaysAgo - prices[i]);
// 更新两天前不持有股票的最大利润
noStockTwoDaysAgo = noStockYesterday;
}
// 返回最后一天不持有股票的最大利润
return noStockToday;
}
}
时间复杂度O(N),空间复杂度O(1)