【面试经典 150 | 动态规划】【每日一题】买卖股票的最佳时机 III

Tag

【动态规划】【数组】【2023-10-03】


题目来源

123. 买卖股票的最佳时机 III


题目解读

有一个表示股票价格的数组,你需要计算出在最多可以完成两笔交易的前提下可获得的最大收益,你必须在再次购买之前卖掉之前的股票。


解题思路

又是认真学习 买卖股票的最佳时机 III 官方题解的一天

方法一:优化后的动态规划

状态

我们在任意的一天交易之后,会有以下五种状态:

  • 没有进行任何交易;
  • 只有过一次买操作,记为 b u y 1 buy_1 buy1
  • 进行了一次买操作和一次买操作,即完成了一笔交易,记为 s e l l 1 sell_1 sell1
  • 在完成看第一笔交易之后,进行了第二次买操作,记为 b u y 2 buy_2 buy2;
  • 完成了全部的两笔交易,记为 s e l l 2 sell_2 sell2

转移关系

如果我们知道了第 i-1 天的这四个状态,那么就可以通过第 i-1 天转移到第 i 天,具体地:

  • 对于 b u y 1 buy_1 buy1:在第 i 天可以不进行任何操作,那么这一天的 b u y 1 buy_1 buy1 等于前一天的只进行一次买操作获得的最大利润,我们记为 b u y 1 ′ buy^{'}_1 buy1;如果在第 i 天只进行了一次买操作,那么这一天的 b u y 1 buy_1 buy1 等于前一天的不进行操作获得的最大利润。因此, b u y 1 = m a x ( b u y 1 ′ , − p r i c e s [ i ] ) buy_1 = max(buy^{'}_1, -prices[i]) buy1=max(buy1,prices[i])
  • 对于 s e l l 1 sell_1 sell1:在第 i 天可以不进行任何操作,那么这一天的 s e l l 1 sell_1 sell1 等于前一天的完成了一笔交易获得的最大利润,我们记为 s e l l 1 ′ sell^{'}_1 sell1;如果在第 i 天只进行了一次卖操作,那么这一天的 s e l l 1 sell_1 sell1 等于前一天的进行一次买操作获得的最大利润。因此, s e l l 1 = m a x ( s e l l 1 ′ , b u y 1 ′ − p r i c e s [ i ] ) sell_1 = max(sell^{'}_1, buy^{'}_1 - prices[i]) sell1=max(sell1,buy1prices[i])
  • 同理可得:
    • b u y 2 = m a x ( b u y 2 ′ , s e l l 1 ′ − p r i c e s [ i ] ) buy_2 = max(buy^{'}_2, sell^{'}_1 - prices[i]) buy2=max(buy2,sell1prices[i])
    • s e l l 2 = m a x ( s e l l 2 ′ , b u y 2 ′ + p r i c e s [ i ] ) sell_2 = max(sell^{'}_2, buy^{'}_2 + prices[i]) sell2=max(sell2,buy2+prices[i])

在考虑边界条件时,我们需要理解下面的这个事实:

无论题目中是否允许「在同一天买入并且卖出」这一操作,最终的答案都不会受到影响,这是因为这一操作带来的收益为零。

因此,最终的状态转移方程为:

{ b u y 1 = max ⁡ ( b u y 1 , − p r i c e s [ i ] ) s e l l 1 = max ⁡ ( s e l l 1 ,   b u y 1 + p r i c e s [ i ] ) b u y 2 = max ⁡ ( b u y 2 , s e l l 1 − p r i c e s [ i ] ) s e l l 2 = max ⁡ ( s e l l 2 , b u y 2 + p r i c e s [ i ] ) \left\{ \begin{array}{c} buy_1=\max \left( buy_1,-prices\left[ i \right] \right)\\ sell_1=\max \left( sell_1,\ buy_1+prices\left[ i \right] \right)\\ buy_2=\max \left( buy_2,sell_1-prices\left[ i \right] \right)\\ sell_2=\max \left( sell_2,buy_2+prices\left[ i \right] \right)\\ \end{array} \right. buy1=max(buy1,prices[i])sell1=max(sell1, buy1+prices[i])buy2=max(buy2,sell1prices[i])sell2=max(sell2,buy2+prices[i])

base case

那么对于边界条件,我们考虑第 =0 的四个状态: b u y 1 buy_1 buy1 为以 p r i c e s [ 0 ] prices[0] prices[0] 价格买入股票,因此 b u y 1 = p r i c e s [ 0 ] buy_1=prices[0] buy1=prices[0] s e l l 1 sell_1 sell1 为同一天买入并卖出 ,因此 s e l l 1 = 0 sell_1 = 0 sell1=0 b u y 2 buy_2 buy2 即为在同一天买入并且卖出后再以 p r i c e s [ 0 ] prices[0] prices[0] 的价格买入股票,因此 b u y 2 = − p r i c e s [ 0 ] buy_2=−prices[0] buy2=prices[0];同理可得 s e l l 2 = 0 sell_2=0 sell2=0

最后返回

在动态规划结束后,由于我们可以进行不超过两笔交易,因此最终的答案在 0 s e l l 1 sell_1 sell1 s e l l 2 sell_2 sell2 中,为三者中的最大值。然而我们可以发现,由于在边界条件中, s e l l 1 sell_1 sell1 s e l l 2 sell_2 sell2 的值已经为 0,并且在状态转移的过程中我们维护的是最大值,因此 s e l l 1 sell_1 sell1 s e l l 2 sell_2 sell2 一定大于等于 0。同时,如果最优的情况对应的是恰好一笔交易,那么它也会因为我们在转移时允许在同一天买入并且卖出这一宽松的条件,从 s e l l 1 sell_1 sell1 转移至 s e l l 2 sell_2 sell2 ,因此最终的答案即为 s e l l 2 sell_2 sell2

实现代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int buy1 = -prices[0], sell1 = 0;
        int buy2 = -prices[0], sell2 = 0;
        for (int i = 1; i < n; ++i) {
            buy1 = max(buy1, -prices[i]);
            sell1 = max(sell1, buy1 + prices[i]);
            buy2= max(buy2, sell1 - prices[i]);
            sell2 = max(sell2, buy2 + prices[i]);
        }
        return sell2;
    }
};

复杂度分析

时间复杂度: O ( n ) O(n) O(n) n n n 为数组 prices 的长度。

空间复杂度: O ( 1 ) O(1) O(1)


写在最后

买卖股票系列题目

题目解答
121. 买卖股票的最佳时机【面试经典150】买卖股票的最佳时机
122. 买卖股票的最佳时机 II【面试经典150】买卖股票的最佳时机 II
188. 买卖股票的最佳时机 IV【每日一题】买卖股票的最佳时机 IV
309. 买卖股票的最佳时机含冷冻期【每日一题】买卖股票的最佳时机含冷冻期
714. 买卖股票的最佳时机含手续费【每日一题】买卖股票的最佳时机含手续费

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wang_nn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值