动态规划
状态定义
题目要求卖出股票的下一天,不能再买入股票。针对这个要求,我们定义两个状态,表示当天的股票状态:
状态0:非持有股票(但不是今天卖出导致非持有,可以是上一天卖出,上上天卖出,或者一直没买过)状态1:持有股票(在状态0(注意是上一天的状态),买入股票(比如9号卖出,11号买入);或者昨天持有股票,今天不卖)
在状态1中,可以看出今天持有股票的状态,均不是由昨天卖出股票,今天买入所转移而来的,这样就避免了在冷冻期买入股票。
- 接着我们可以再使用一个
状态2表示,今天卖出股票。
dp数组定义
有了上述三个状态后,我们就可以来定义dp数组。
dp[i][0]:第i天非持有股票时,所具有的最大收益dp[i][1]:第i天持有股票时,所具有的最大收益dp[i][2]:第i天卖出股票时,所具有的最大收益
dp数组初始化
第一天只能买入
dp[0][0] = 0dp[0][1] = -prices[0]dp[0][2] = 0
状态如何转移?
dp[i][0](今天不持有股票,最大收益是多少?):
- 昨天不持有,今天继续不买入;
- 昨天卖出股票。
也就是上一天dp[i - 1][0]和dp[i - 1][2]中的最大值。
dp[i][1](今天持有股票,最大收益是多少?):
- 昨天持有,今天不卖;
- 昨天不持有,今天买入。
也就是上一天dp[i - 1][1]和dp[i - 1][0] - prices[i](注意是减,买入股票要花钱,是负收益)中的最大值。
dp[i][2](今天卖股票,最大收益是多少?):今天卖出股票。dp[i - 1][1] + prices[i]
填完dp表后,返回dp[n - 1][0]和dp[n - 1][2]中的最大值,也就是手中没有股票时的最大收益。
由右下角往上反推,就能找到最佳时机路径:买入->卖出->冷冻->买入->卖出
class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
if (n == 1) {
return 0;
}
int[][] dp = new int[n][3];
dp[0][0] = 0;
dp[0][1] = -prices[0];
dp[0][2] = 0;
for (int i = 1; i < n; i++) {
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2]);
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
dp[i][2] = dp[i - 1][1] + prices[i];
}
return Math.max(dp[n - 1][0], dp[n - 1][2]);
}
}