Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
前言
力扣第123题 买卖股票的最佳时机 III
如下所示:
给定一个数组,它的第 i
个元素是一支给定的股票在第 i
天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
一、思路
这一题与前面一题# 力扣第122题-买卖股票的最佳时机 II思路非常相似,我们只需要把握题目的重点信息:同一天有且仅能持有一支股票,或不持有股票,也就是说我们不能连续的买入或连续的卖出。
我们将股票分割为每天来看的话,对于每一天来说我们会有以下五个状态:
- 什么都不做,利润会一直为
0
- 第一次买入
- 第一次卖出
- 第二次买入
- 第二次卖出
第一种状态我们暂时可以忽略不做考虑,重点关注下面的四种状态。
如果我们可以确定前一天的状态,那么很轻松就可以推算出今天的利润情况。状态转移的情况如下:
今天第一次买入
为保持不动或买入今天的股票
(今天的股票可能会更便宜,买更便宜的才能让利润最大化)今天第一次卖出
为之前卖过一次或之前买过一次今天卖掉
今天第二次买入
为保持不动或买入今天的股票
今天第二次卖出
为之前卖过两次或之前买过二次今天卖掉
动态规划
我们根据上面的推理很轻易的就能使用 动态规划
来解决此题目了。我们设 dp[][4]
中的四行分别对应 第一次买
、第一次卖
、第二次买
、第二次卖
处理边界情况
当第一天 i=0
时,只能够买入,故 dp[0][0] = -prices[0]
状态转移方程
dp[i][0] = Math.max(dp[i-1][0], -prices[i])
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i])
dp[i][2] = Math.max(dp[i-1][2], dp[i-1][1] - prices[i])
dp[i][3] = Math.max(dp[i-1][3], dp[i-1][2] + prices[i])
复制代码
为了更好的显示表示某哥操作没有发生,我们将数组的默认值统一设置为 null
。故在处理第二次买和第二次卖的时候需要对于前一天的第一次卖和第二次买进行非空的判断!
二、实现
实现代码
实现的代码与思路中完全保持一致,效率上虽然低了一点,但是能更好的理解动态规划的过程。
public int maxProfit(int[] prices) {
int len = prices.length;
Integer[][] dp = new Integer[len][4];
dp[0][0] = -prices[0]; // 第一天只能买
// 处理返回值,防止空指针
dp[len-1][1] = -1;
dp[len-1][3] = -1;
for (int i = 1; i < len; ++i) {
// 保持不动或买入今日的股票
dp[i][0] = Math.max(dp[i-1][0], -prices[i]);
// 之前卖过一次或之前买过一次今天卖掉
if (dp[i-1][1] == null){
dp[i][1] = dp[i-1][0] + prices[i];
}else {
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i]);
}
// 保持不动或之前买过一次今天买入
if (dp[i-1][1] != null){
if (dp[i-1][2] != null){
dp[i][2] = Math.max(dp[i-1][2], dp[i-1][1] - prices[i]);
}else {
dp[i][2] = dp[i-1][1] - prices[i];
}
}
// 之前卖过两次或今天继续卖出
if (dp[i-1][2] != null){
if (dp[i-1][3] != null){
dp[i][3] = Math.max(dp[i-1][3], dp[i-1][2] + prices[i]);
}else {
dp[i][3] = dp[i-1][2] + prices[i];
}
}
}
return Math.max(Math.max(dp[len-1][1], dp[len-1][3]) , 0);
}
复制代码
测试代码
public static void main(String[] args) {
int[] nums = {3,3,5,0,0,3,1,4};
int[] nums1 = {1,2,3,4,5};
int[] nums2 = {1};
new Number123().maxProfit(nums2);
}
复制代码
结果
三、总结
感谢看到最后,非常荣幸能够帮助到你~♥
如果你觉得我写的还不错的话,不妨给我点个赞吧!如有疑问,也可评论区见~