• 从零备战蓝桥杯——动态规划(股票问题)



    双非刷leetcode备战2023年蓝桥杯,qwq加油吧,无论结果如何总会有收获!一起加油,我是跟着英雄哥的那个思维导图刷leetcode的,大家也可以看看所有涉及到的题目用leetcode搜索就可以哦,因为避让添加外链,一起加油!!!

    请添加图片描述

    动态规划之股票问题



    股市有风险,投资需谨慎

    刷题虽简单,基金绿一半


    总体思路:

    dp方程就是这个问题有哪几个状态比如股票的话就有持有不持有,卖不卖,等状态在一个问题具有多状态时我们就可以使用dp来做!dp[一个状态][一个状态][一个状态]然后dp代表什么最大啊最小啊什么的然后再找状态转移方程,比如我今天卖,或者是我之前就卖了,等情况,把这些情况都列出来我们基本就能解决大部分dp问题了如股票第三题。
    
    • 1

    leetcode 121. 买卖股票的最佳时机

    心路历程:我一看这个题,我直接暴力,肯定超时,结果还真超时了,不过他说简单,我以为真能混来。
    那我这是动态规划只能dp了搞个dp数组把

    五步走战略:

      1. 确定dp数组下标含义 :到第i天的最大利润
      1. 递推公式 dp[i]=max(dp[i-1],prices[i]-min);
      1. 初始化 设个min来记录当前之前的最小值 初始化为prices[0],初始化dp数组0;
      1. 遍历顺序 for(int i=1;i
      1. 推导结果 return dp[prices.size()-1];
        没啥难的,就记录一下最小值然后用当天的减去最小值和上一个比较一下就行了,好像都不用dp数组就可以,因为取最大值,我们直接搞个int max来记录就完事了
        我第一次写的dp数组版:
    class Solution {
    public:
       int maxProfit(vector<int>& prices) {
    
           vector<int> dp(prices.size()+1,0);
    
           int min=prices[0];
           for(int i=1;i<prices.size();i++)
       {
           if(prices[i]<min)
           {
               min=prices[i];
           }
           dp[i]=max(dp[i-1],prices[i]-min);
       }
       return dp[prices.size()-1];
       }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    把dp数组换成max的版:

    public class Solution {
        public int maxProfit(int prices[]) {
            int minprice = Integer.MAX_VALUE;
            int maxprofit = 0;
            for (int i = 0; i < prices.length; i++) {
                if (prices[i] < minprice) {
                    minprice = prices[i];
                } else if (prices[i] - minprice > maxprofit) {
                    maxprofit = prices[i] - minprice;
                }
            }
            return maxprofit;
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    第一次买股票自己就会买了,真好,不愧是简单题:


    122. 买卖股票的最佳时机 II

    我觉得吧,只要后一天比前一天的钱数大咱就赚了,因为我们可以随便买,怎么说呢举个例子。

    [7, 1, 5, 6] 第二天买入,第四天卖出,收益最大(6-1)=5,所以有些人可能会想,怎么判断不是第三天就卖出了呢? 这里就把问题复杂化了,根据题目的意思,当天卖出以后,当天还可以买入,所以其实可以第三天卖出,第三天买入,第四天又卖出(5-1)+ (6-5) = 6 - 1。所以算法可以直接简化为只要今天比昨天大,就卖出。这样就就能直接搞了

    直接看代码:

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

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

    我c困难题,不想做了,想直接看答案了,不过还是想想吧。

    我不会!!!看题解!!!好简单!!!我会了!!!下一次!!!我不会!!!

    思路: 首先dp是什么是状态转移方程有哪些状态dp[第几天][当前是否持股][卖出的次数]

    状态转移方程就挨个写出来就完事了:看看我下面写的代码里面的注释应该就知道分几种情况了!把所有情况考虑清楚就ok了

    	    dp[i][0][0]=0;//我害怕,我没钱买卖,啥也没干
            dp[i][0][1]=max(dp[i-1][0][1],dp[i-1][1][0]+prices[i]);//我没持股但我卖出去过1次,可能是以前卖的(前)可能是今天卖的(后)
            dp[i][0][2]=max(dp[i-1][0][2],dp[i-1][1][1]+prices[i]);//我没持股但我卖出去过1次,可能是以前卖的(前)可能是今天卖的(后)
            dp[i][1][0]=max(dp[i-1][1][0],dp[i-1][0][0]-prices[i]);//我持股但我卖,可能是以前买的(恒大)可能是今天我算卦了这个肯定涨今天买的
            dp[i][1][1]=max(dp[i-1][1][1],dp[i-1][0][1]-prices[i]);//我持股但我卖出去过1次,可能是以前买的(恒大)可能是今天我算卦了这个肯定涨今天买的
            dp[i][1][2]=INT_MIN;//我持股但我卖出去过2次,不可能!我怎么可能卖出去两次还持股
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            vector<vector<vector<int>>> dp(prices.size(),vector<vector<int>>(2, vector<int> (3,0)));
            //初始化第一天的状态
            dp[0][0][0]=0;//第一天不买不卖
            dp[0][1][0]=-prices[0];//第一天买了
            dp[0][0][1]=INT_MIN+100000;//第一天不可能卖1次
            dp[0][0][2]=INT_MIN;//第一天不可能卖2次
            dp[0][1][1]=INT_MIN;//第一天不可能已经卖出
            dp[0][1][2]=INT_MIN;//第一天不可能已经卖出2次
            //直接状态转移
            for(int i=1;i<prices.size();i++)
            {
                dp[i][0][0]=0;//我害怕,我没钱买卖,啥也没干
                dp[i][0][1]=max(dp[i-1][0][1],dp[i-1][1][0]+prices[i]);//我没持股但我卖出去过1次,可能是以前卖的(前)可能是今天卖的(后)
                dp[i][0][2]=max(dp[i-1][0][2],dp[i-1][1][1]+prices[i]);//我没持股但我卖出去过1次,可能是以前卖的(前)可能是今天卖的(后)
                dp[i][1][0]=max(dp[i-1][1][0],dp[i-1][0][0]-prices[i]);//我持股但我卖,可能是以前买的(恒大)可能是今天我算卦了这个肯定涨今天买的
                dp[i][1][1]=max(dp[i-1][1][1],dp[i-1][0][1]-prices[i]);//我持股但我卖出去过1次,可能是以前买的(恒大)可能是今天我算卦了这个肯定涨今天买的
                dp[i][1][2]=INT_MIN;//我持股但我卖出去过2次,不可能!我怎么可能卖出去两次还持股
            }
            return max(max(dp[prices.size()-1][0][2],dp[prices.size()-1][0][1]),0);
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    这样写是不是太麻烦了,还可以用循环整理一下:

    class Solution {
    public:
        int maxProfit( vector<int>& prices) {
        int dp[prices.size()][3][2];
            // int dp[prices.size()][k+1][2];//dp[天数][能买的次数][是否持股]
            //第一天:初始化
            for(int i=0;i<=2;i++)
            {
                dp[0][i][0]=0;//不持股只可能是0
                dp[0][i][1]=-prices[0];//持股只可能是第一天买的
            }
                for (int i = 1; i < prices.size(); i++) {//当k=0时也要初始化不然下面会用到
                dp[i][0][0] = 0;//啥也没干
                dp[i][0][1] = max(dp[i - 1][0][1], dp[i - 1][0][0] - prices[i]);//我持股了,可能是以前买的也可能是今天买的
            }
    
     
                for(int i=1;i<prices.size();i++)//循环天数
                {
                    for(int j=1;j<=2;j++)//循环交易次数,这里注意要规定买或卖为一次交易
                    {
                        //不持股,可能是之前卖的,可能是今天卖的
                        dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j-1][1]+prices[i]);
                        //持股,可能是之前买的,可能是今天买的
                        dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j][0]-prices[i]);
                    }
                }
            return dp[prices.size()-1][2][0];
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    188. 买卖股票的最佳时机 IV

    我c,又是个困难题,不过应该不会很困难吧,不会吧不会吧!
    Ooooo ,和上一个题一模一样的!!大水题!上一个题你会了,这个题你就会了。

    思路:把上一个题的2次改成k次;

    直接上代码:

    class Solution {
    public:
        int maxProfit(int k, vector<int>& prices) {
               vector<vector<vector<int>>> dp(prices.size(),vector<vector<int>>(k+1, vector<int> (2,0)));
            // int dp[prices.size()][k+1][2];//dp[天数][能买的次数][是否持股]
            //第一天:初始化
            for(int i=0;i<k;i++)
            {
                dp[0][i][0]=0;//不持股只可能是0
                dp[0][i][1]=-prices[0];//持股只可能是第一天买的
            }
      
                for(int i=1;i<prices.size();i++)//循环天数
                {
                    for(int j=0;j<k;j++)//循环交易次数,这里注意要规定买或卖为一次交易
                    {
                        //不持股,可能是之前卖的,可能是今天卖的
                        dp[i][k][0]=max(dp[i-1][k][0],dp[i-1][k][1]+prices[i]);
                        //持股,可能是之前买的,可能是今天买的
                        dp[i][k][1]=max(dp[i-1][k][1],dp[i-1][k-1][1]-prices[i]);
                    }
                }
            return dp[prices.size()-1][k-1][0];
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    上面两个题告诉你告诉你做一个动态规划题一定要看好他的几个状态以及在这种状态下的情况


    714. 买卖股票的最佳时机含手续费

    这个题更简单了,直接自己写出来。因为可以无限购买,反而不用考虑交易次数了,所以本题只需要考虑两个状态

    状态方程: dp[天数][持有数]

    初始化:我们需要初始化第一天的:
    dp[0][0]=0;//第一天啥也不干 dp[0][1]=-prices[0]-fee;//第一天买要注意手续费

    状态转移方程:

    			dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);//不持有,有可能今天卖了也就可能之前卖的;
                dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]-fee);//持有,有可能是今天买的也有可能是以前买的;要注意手续费
    
    • 1
    • 2

    直接看代码:

    
    
    class Solution {
    public:
        int maxProfit(vector<int>& prices, int fee) {
            int num = prices.size();
            int dp[num][2];
            dp[0][0]=0;//第一天啥也不干
            dp[0][1]=-prices[0]-fee;//第一天买
            for(int i=1;i<num;i++)
            {
                dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);//不持有,有可能今天卖了也就可能之前卖的;
                dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]-fee);//持有,有可能是今天买的也有可能是以前买的;
            }
            return dp[num-1][0];
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    309. 最佳买卖股票时机含冷冻期

    思路:

    状态方程: dp[天数][不持有冷冻期,不持有非冷冻期,持有]

    初始化:我们需要初始化第一天的:
    int dp[num][3] ;//0表示不持有,1表示持有,2表示不持有正在冷冻期;
    dp[0][0]=0;//第一天啥也不干
    dp[0][1]=-prices[0];//第一天买
    dp[0][2]=INT_MIN;//不可能有冷冻期

    状态转移方程:

    dp[i][0]=max(dp[i-1][0],dp[i-1][2]);//我不持有了,而且我还不是冷冻期 1.不可能是今天卖的(冷冻期的情况就变成dp[i][2]了),2.可能是以前已经卖的,3.可能是前一天是冷冻期我卖了的
    dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);//我持有了,可能是之前买的可能是今天没有冷冻期我刚买的
    dp[i][2]=dp[i-1][1]+prices[i];//我冷冻期了肯定是前一天卖的我不能买了也不能卖了只能继承了
    
    • 1
    • 2
    • 3

    直接看代码:

    
    
    class Solution {
    public:
        int maxProfit(vector<int>& prices) {
            int num=prices.size();
            int dp[num][3];//0表示不持有,1表示持有,2表示不持有正在冷冻期;
            dp[0][0]=0;//第一天啥也不干
            dp[0][1]=-prices[0];//第一天买
            dp[0][2]=INT_MIN;//不可能有冷冻期
            for(int i=1;i<num;i++)
            {
                dp[i][0]=max(dp[i-1][0],dp[i-1][2]);//我不持有了,而且我还不是冷冻期 1.不可能是今天卖的(冷冻期的情况就变成dp[i][2]了),2.可能是以前已经卖的,3.可能是前一天是冷冻期我卖了的
                dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);//我持有了,可能是之前买的可能是今天没有冷冻期我刚买的
                dp[i][2]=dp[i-1][1]+prices[i];//我冷冻期了肯定是前一天卖的我不能买了也不能卖了只能继承了
            }
            return max(dp[num-1][0],dp[num-1][2]);//考虑之前卖了的和刚刚卖是冷冻期两种情况
        }
    };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    这个题也是比较简单的,只要考虑前一天是不是冷冻期就好了;根据这个题我们可以发现其实
    前面的两个三维数组的dp的空间可以简化成二维数组的,甚至这个题也可以简化成一维数组的
    形式,各位读者可以尝试一下并在评论区给出你的答案;


    好了这六种股票问题就到这里了,其实股票问题的关键就是对状态的把握,持有不持有,冷不冷冻期等等等等,只要把握好这些状态,其实不管用一维数组还是二维数组都能比较简单的做出股票相关的题目~~,如有错误和改进的地方欢迎在评论区指正。


    在这里插入图片描述

    Love is worth years.❤
    热爱可抵岁月漫长。

    ​​​​
    本文部分思路来源于网络(做力扣看题解!)如有侵权联系删除~

  • 相关阅读:
    RabbitMQ系列【15】AmqpAdmin使用详解
    如何使用Puppeteer进行新闻网站数据抓取和聚合
    讲讲项目里的仪表盘编辑器(三)布局组件
    Golang学习日志 ━━ 部署Gin-Vue-Admin到windows系统并启用IIS服务,顺便学习如何设置IIS反向代理
    Java设计模式七大原则-里氏替换原则
    腾讯云国际云服务器登录之后没有网络,如何排查?
    NISP和CISP网络安全高级运维工程师需要掌握的应急响应有什么方向
    【LeetCode】每日一题 2023_11_16 最长奇偶子数组(枚举,模拟)
    Linux高性能服务器编程 学习笔记 第三章 TCP协议详解
    数据结构中的树和二叉树(0基础讲解+代码)
  • 原文地址:https://blog.csdn.net/m0_63830846/article/details/127653100