leetcode:123. 买卖股票的最佳时机 III(最多买卖两次,允许同一天多次操作但是不允许同时持有多张股票)

题目来源

题目描述

在这里插入图片描述
在这里插入图片描述

题目解析

(1) dp数组的定义

  • 由于我们最多可以完成两笔交易,因此在任意一天结束之后,我们会处于下面五种状态中的一种
    • :未进行任何操作
    • buy1[i]:只进行过一次买操作
    • sell1[i]:进行了一次买操作和一次卖操作,即完成了一笔交易
    • buy2[i]:在完成了一笔交易的情况下,进行了第二次买操作
    • sell2[i]:完成了全部两笔交易
  • 由于我们第一个状态的利润显然是0,因此我们可以不用将其记录。对于剩下的四个状态,我们分别将它们的最大利润记为:buy1[i]、sell1[i],buy2[i],sell2[i]

(2)状态转移方程的推导

  • buy1[i]:
    • 今天买入股票,那么buy1[i] = - prices[i]
    • 今天没有操作,那么buy1[i] = buy1[i - 1]
    • 上面两者中选一个大的: buy1[i] = std::max(buy1[i - 1], -prices[i]);
  • sell1[i]:
    • 今天卖出股票,那么sell1[i] = buy1[i - 1] + prices[i]
    • 今天没有操作,那么sell1[i] = sell1[i - 1]
    • 上面两者中选一个大的
  • buy2[i]:
    • 今天买入股票,那么buy2[i] = sell1[i - 1] - prices[i]
    • 今天没有操作,那么沿用之前的:buy2[i] = buy2[i - 1]
    • 上面两者中选一个大的
  • sell2[i]:
    • 今天卖出股票,那么sell2[i] = buy2[i - 1] - prices[i]
    • 今天没有操作,那么sell2[i] = sell2[i - 1]
    • 上面两者中选一个大的

(3)dp数组如何初始化

  • 先来明确下题目中的隐含条件:无论题目是否允许[在同一天买入卖出]这一操作,最终答案都不会被影响,因为这一操作带来的收益为0。为了方便初始化,默认是允许的,因此:
    • buy1[0]:以prices[0]的价格买入股票:buy1[0] = -prices[0]
    • sell1[0]:在同一天买入卖出:sell1[0] = 0
    • buy2[0]:在同一天买入后卖出再以prices[0]的价格买入股票:buy2[0] = -prices[0]
    • sell2[0]:sell2[0] = 0
  • 如果题目不允许的话, 那初始化就会稍微麻烦一些了, 比如sell1[i]就只能在第二天进行sell1[1]的初始化了, 同理: buy2[i]在第三天进行buy2[2]的初始化, sell2[i]在第四天进行sell2[3]的初始化, 这就是能否「在同一天买入并且卖出」的不同之处.

(4)最终结果

  • 在动态规划结束后,由于我们可以进行不超过两笔交易,因此最终的答案在0,sell1[i],sell2[i]中, 且为三者中的最大值, 由于在边界条件中sell1[i],sell2[i]的值已经为0, 并且在状态转移的过程中我们维护的是最大值, 因此sell1[i],sell2[i]最终一定大于等于0.
  • 同时, 如果最优的情况对应的是恰好一笔交易, 那么它也会因为我们在转移时允许在同一天买入并且卖出这一宽松的条件, 从sell1[i]转移至sell2[i], 可以理解假如最优是 sell1[i] 的话, 可以当天再做一次买卖, 也就是完成两次交易, 所以无论如何都可以是 sell2[i] 最优.
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        std::vector<int> buy1(n), sell1(n);
        std::vector<int> buy2(n), sell2(n);
        buy1[0] = -prices[0]; sell1[0] = 0;
        buy2[0] = -prices[0]; sell2[0] = 0;
        for (int i = 1; i < n; ++i) {
            buy1[i] = std::max(buy1[i - 1], -prices[i]);
            sell1[i] = std::max(sell1[i - 1], buy1[i - 1] + prices[i]);
            buy2[i] = std::max(buy2[i - 1], sell1[i - 1] - prices[i]);
            sell2[i] = std::max(sell2[i - 1], buy2[i - 1] + prices[i]);
        }

        return sell2[n - 1];
    }
};

类似题目

题目
leetcode:188. 买卖股票的最佳时机 IV(最多买卖k次),允许同一天多次操作但是不允许同时持有多张股票 Best Time to Buy and Sell Stock IV
leetcode:121. 买卖股票的最佳时机(最多买卖1次(k == 1),允许同一天多次操作但是不允许同时持有多张股票) Best Time to Buy and Sell Stock
leetcode:122. 买卖股票的最佳时机 II(最多买卖多次(k=+∞),允许同一天多次操作但是不允许同时持有多张股票)Best Time to Buy and Sell Stock II
leetcode:123. 买卖股票的最佳时机 III(最多买卖两次(k == 2),允许同一天多次操作但是不允许同时持有多张股票)Best Time to Buy and Sell Stock III
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值