• LeetCode 0123.买卖股票的最佳时机III:常数空间下的动态规划+模拟


    【LetMeFly】123.买卖股票的最佳时机 III:常数空间下的动态规划+模拟

    力扣题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/

    给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

    设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

    注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

     

    示例 1:

    输入:prices = [3,3,5,0,0,3,1,4]
    输出:6
    解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
         随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。

    示例 2:

    输入:prices = [1,2,3,4,5]
    输出:4
    解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。   
         注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。   
         因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
    

    示例 3:

    输入:prices = [7,6,4,3,1] 
    输出:0 
    解释:在这个情况下, 没有交易完成, 所以最大利润为 0。

    示例 4:

    输入:prices = [1]
    输出:0
    

     

    提示:

    • 1 <= prices.length <= 105
    • 0 <= prices[i] <= 105

    方法一:常数空间下的动态规划

    这道题说白了最多有 5 5 5个状态:

    • 未进行过任何交易
    • 进行了一次买入
    • 进行了一次买卖
    • 进行了一次买卖 + 一次买入
    • 进行了两次买卖

    未进行任何交易时,所获利为 0 0 0,因此无需特别关注。

    用四个变量 b u y 1 , s e l l 1 , b u y 2 , s e l l 2 buy1, sell1, buy2, sell2 buy1,sell1,buy2,sell2分别代表交易进行到剩下的四种状态时,当前获利的最大值。(这里变量名尽量与官方题解保持一致)

    接下来我们严格遵守上述四个变量的含义

    将四个变量的初始值赋值为第一天过后的最大获利值:

    • b u y 1 buy1 buy1:第一天进行了一次买入。那么当前最大获利为 负的第一天的股价 负的第一天的股价 负的第一天的股价(说是最大获利,其实第一天进行到这种状态的话别无选择,只有这一种获利结果)
    • s e l l 1 sell1 sell1:第一天进行了一次买卖。那么买入和卖出的价格相同,当前最大获利为 0 0 0
    • b u y 2 buy2 buy2:第一天进行了一次买卖 + 一次买入。也就是说第一天买了一次立刻卖了,然后又买了一次,总(最大)获利为 负的第一天的股价 负的第一天的股价 负的第一天的股价
    • s e l l 2 sell2 sell2:第一天进行了两次买卖。总收益为 0 0 0
    int buy1 = -prices[0]
    int sell1 = 0;
    int buy2 = -prices[0]
    int sell2 = 0;
    
    • 1
    • 2
    • 3
    • 4

    接下来,从第 2 2 2天开始,模拟前 i i i天,每种状态下的最大获利。

    • b u y 1 buy1 buy1:前 i i i天只进行过一次买入的最大获利。 b u y = max ⁡ ( b u y ′ , − p r i c e s [ i ] ) buy=\max(buy', -prices[i]) buy=max(buy,prices[i])。也就是说,可以是前 i − 1 i-1 i1天股价较低的时候进行一次买入( b u y ′ buy' buy),也可以不在前 i − 1 i-1 i1天买而是在第 i i i天买入( − p r i c e s [ i ] -prices[i] prices[i])。(这里用 b u y ′ buy' buy代表第 i − 1 i-1 i1天时 b u y buy buy的值)
    • s e l l 1 sell1 sell1:前 i i i天进行过一次买卖。 s e l l 1 = max ⁡ ( s e l l 1 ′ , b u y 1 ′ + p r i c e s [ i ] ) sell1=\max(sell1', buy1' + prices[i]) sell1=max(sell1,buy1+prices[i])。也就是说,可以是在前 i − 1 i-1 i1天进行了一次买卖而今天不进行任何操作( s e l l 1 ′ sell1' sell1),也可以是前 i − 1 i-1 i1天只进行了买入而在第 i i i天卖出( b u y 1 ′ + p r i c e s [ i ] buy1'+prices[i] buy1+prices[i])(卖出会获利 p r i c e s [ i ] prices[i] prices[i]
    • b u y 2 buy2 buy2:前 i i i天进行过一次买卖+一次买入。 b u y 2 = max ⁡ ( b u y 2 ′ , s e l l 1 ′ − p r i c e s [ i ] ) buy2=\max(buy2', sell1'-prices[i]) buy2=max(buy2,sell1prices[i])。也就是说,可以是在前 i − 1 i-1 i1天进行了一次买卖+一次买入而今天不进行任何操作( b u y 2 ′ buy2' buy2),也可以是前 i − 1 i-1 i1天进行了一次买卖而在第 i i i天又买入了一次( s e l l 1 ′ + ( − p r i c e s [ i ] ) sell1' + (-prices[i]) sell1+(prices[i]))(买入会支出 p r i c e s [ i ] prices[i] prices[i]
    • s e l l 2 sell2 sell2:前 i i i天进行了两次买卖。 s e l l 2 = max ⁡ ( s e l l 2 ′ , b u y 2 ′ + p r i c e s [ i ] ) sell2=\max(sell2',buy2'+prices[i]) sell2=max(sell2,buy2+prices[i])。可以是在前 i − 1 i-1 i1天进行了两次买卖而今天不进行任何操作( s e l l 2 ′ sell2' sell2),也可以是前 i − 1 i-1 i1天只进行了一次买卖+一次买入而在第 i i i天卖出了第二次买入( b u y 2 ′ + p r i c e s [ i ] buy2'+prices[i] buy2+prices[i])(卖出会获利 p r i c e s [ i ] prices[i] prices[i]

    因此,模拟完 n n n天后,返回 s e l l 2 sell2 sell2即可(进行了两次买卖)

    注意,题目中是最多进行两次买卖,也就是说可以只进行一次买卖或不进行任何买卖。不进行买卖和买入的当天卖出是等价的,因此可以理解为必须进行了两次买卖但可能买入的同一天卖出过。

    • 时间复杂度 O ( n ) O(n) O(n)
    • 空间复杂度 O ( 1 ) O(1) O(1),只使用了常数个额外空间

    AC代码

    C++

    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int buy1 = -prices[0], sell1 = 0;
            int buy2 = -prices[0], sell2 = 0;
            for (int i = 1; i < prices.size(); i++) {
                buy1 = max(buy1, 0 + (-prices[i]));
                sell1 = max(sell1, buy1 + (prices[i]));
                buy2 = max(buy2, sell1 + (-prices[i]));
                sell2 = max(sell2, buy2 + (prices[i]));
            }
            return sell2;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    代码很短,关键在于严格遵守变量的定义并理解。

    同步发文于CSDN,原创不易,转载请附上原文链接哦~
    Tisfy:https://letmefly.blog.csdn.net/article/details/125889831

  • 相关阅读:
    【前端笔记】SCSS学习篇之一:基础入门
    通达信接口公式怎样进行破解?
    go gorm select * 优化
    4年博主写博客的折腾之路
    liunx的三个时间atime,mtime,ctime详细说明与使用场景
    ArmSoM Rockchip系列产品 通用教程 之 Display 使用
    springboot+java+ssm高校学生学籍档案信息管理系统3cvy3
    按照规则来,为什么还是提图片必须是一条字符串啊!
    在Swift中集成Socket.IO进行实时通信
    组合系列--有排列就有组合
  • 原文地址:https://blog.csdn.net/Tisfy/article/details/125889831