LeetCode-309. 最佳买卖股票时机含冷冻期
-.- 这题不会做,记录下大佬的题解(难度:中等)
一、题目内容
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
二、题解过程
1、问题分析
求最值问题最先想到的就是动态规划问题。动态规划的核心问题就是穷举。因为要求最值,肯定要把所有可行的答案穷举出来,然后求最值。但是动态规划有点特别,因为这类问题存在[重叠子问题],如果暴力穷举的话,效率会及其底下,所以需要[备忘录]或者[DP table]来优化穷举过程,避免不必要的计算。
2、转态定义
我们可以考虑用dp[i]来表示第 i 天结束后的最大收益,根据题意我们当天共有三种状态,持有,卖出冻结,卖出未冻结,此状态影响状态转移,因此我们会有三种不同的状态:
1)持有股票,对应的最大累计收益为dp[i][0];
2)卖出股票,处于冷冻期,手头为空,第二天不可交易,对应的最大累计收益为dp[i][1];
3)卖出股票,不处于冷冻期,第二天可交易,对应的最大累计收益为dp[i][2];
3、状态转移
如何进行转移呢?在第 i 天的时候,我们可以在不违反规则的情况下,进行买入或者卖出的操作,此时第 i 天的转态是由第 i-1 天的状态转移的;我们也可以不进行任何操作,则第 i 天的状态就是第 i-1 天的状态,我们分别对这三种状态进行分析:
1)对于dp[i][0],我们目前持有一支股票,可以假设第 i-1 天已经持有,则对应的状态为dp[i-1][0];也可以假设第 i 天买入这支股票,则对应的状态为dp[i-1][2] 加上买入这支股票的带来的负收益price[i]。因此状态转移方程为:
dp[i][0] = max(dp[i-1][0],dp[i-1][2] - price[i])
2) 对于dp[i][1],我们在第i天结束之后处于冷冻期的原因是在当天卖出了股票,因此在 i-1天必须持有一支股票,对应的状态为dp[i-1][0],加上当天卖出股票的正向收益price[i-1]。因此状态转移方程为:
dp[i][1] = dp[i-1][0] + price[i]
3) 对于dp[i][2],当前不持有股票,并且不可交易,则在第 i-1 天时不持有任何股票,如果处于冷冻期,则对应的状态为dp[i-1][1],如果不处于冷冻期,则对应的状态为dp[i-1][2]。因此状态转移方程为:
dp[i][2] = max(dp[i-1][1],dp[i-1][2])
注意到如果在最后一天 (第 i -1天) 结束之后,手上仍然持有股票,那么显然没有任何意义。因此更加精确的,最终的答案实际上是:
max(dp[i-1][1],dp[i-1][2])
我们可以选择将第1天的情况作为动态规划中的边界条件:
dp[0][0] = -price[0]
dp[0][1] = 0
dp[0][2] = 0
4、解法一代码:
时间复杂度是 O(n^2),n 为待匹配字符串的长度。
// A code block
Class Solution{
public int maxProfit(int[] prices){
if(prices.length == 0){
return 0;
}
int n = prices.length;
int[][] dp = new int[n][3];
dp[0][0] = -prices[0];
for(int i=1;i<n;i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][2] - prices[i]);
dp[i][1] = dp[i-1][0] + prices[i];
dp[i][2] = Math.max(dp[i-1][1],dp[i-1][2]);
}
return Math.max(dp[n-1][1],dp[n-1][2]);
}
}
5、优化方法
注意到上面的状态转移方程中,dp[i]只有dp[i-1]有关,而与之前所有的状态都无关,因此不必计算这些状态的存储态。
Class Solution{
public int maxProfit(int[] prices){
if(prices.length == 0){
return 0;
}
int n = prices.length;
int f0 = -prices[0];
int f1 = 0;
int f2 = 0;
for (int i = 1; i < n; ++i) {
int newf0 = Math.max(f0, f2 - prices[i]);
int newf1 = f0 + prices[i];
int newf2 = Math.max(f1, f2);
f0 = newf0;
f1 = newf1;
f2 = newf2;
}
return Math.max(f1, f2);
}
}
参考如下:
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/solution/zui-jia-mai-mai-gu-piao-shi-ji-han-leng-dong-qi-4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。