给定一个整数数组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+1][5];
// dp[i][j]表示当前剩余的最大现金
// j表示 第i天的状态,
// 0 表示持有股票
// 1 表示保持卖出状态(不持有股票, 在之前就已经卖过了)
// 2 表示当天卖出股票
// 3 表示 冷冻期(只有一天)
// 冷冻期的前一天只能是 [当天卖出股票]
dp[0][0]=-prices[0];
for(int i=1;i<n;i++){
dp[i][0]=Math.max(Math.max(dp[i-1][0],dp[i-1][1]-prices[i])
,dp[i-1][3]-prices[i]);
dp[i][1]=Math.max(dp[i-1][1],dp[i-1][3]);
dp[i][2]=dp[i-1][0]+prices[i];
dp[i][3]=dp[i-1][2];
}
return Math.max(Math.max(dp[n-1][1],dp[n-1][2]),dp[n-1][3]);
}
}
有关于买卖股票的题目 , 一般我们都采用DP的做法。
本题的关键在于如何来确定 每一天 可能会存在的状态
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
**注意:**你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
首先最基本的我们可以通过题目确定两种状态 对于 i 天
- 持有股票
- 不持有股票
其次是关于冷冻期
- 当天是冷冻期
也有可能当天我们进行的操作
- 当天卖出
- 当天购买
其中 当天购买
可以归类为 持有股票 , 但是对于 当天卖出
需要特别作为一种状态(因为存在冷冻期)
那么我们定义DP 数组如下
定义dp[i][j]
, 其中
j表示 第i天的状态,
- 0 表示持有股票
- 1 表示保持卖出状态(不持有股票, 在之前就已经卖过了)
- 2 表示当天卖出股票
- 3 表示 冷冻期(只有一天)
接下来讨论如何进行状态转移
对于 dp[i][0]
, 能转移成此状态的前置状态可能为
dp[i-1][0]
: 第i天我们什么也不做dp[i-1][1] - prices[i]
: 第i天我们购入股票dp[i-1][3] - prices[i]
: i-1天是冷冻期, 我们在第i天购入股票
以上三种我们取最大值即可
对于dp[i][1]
有 dp[i][1]=Math.max(dp[i-1][1],dp[i-1][3]);
- 可能
保持之前的卖出状态
or在 i-1天卖出
最后的两种状态:
dp[i][2]=dp[i-1][0]+prices[i];
: 前一天持有股票, 今天卖出dp[i][3]=dp[i-1][2];
: 前一天卖出 , 今天就是冷冻期
如何初始化:
对于状态的含义 , 首先可以初始化dp[0][0]=-prices[i]
对于 状态2 3 在第一天无法达到 , 因此 初始化为0
需要注意的是状态1 , 我们可以参考状态转移的方程 , 对于第二天 , 保持卖出状态要求前一天之前已经卖出, 而不是前一天卖出, 因此 初始化dp[0][1]=0
最后返回结果 在 完成交易的几种状态中取最大值返回即可
return Math.max(Math.max(dp[n-1][1],dp[n-1][2]),dp[n-1][3]);