所有股票问题(动规)(代码片段)

两片空白 两片空白     2022-12-19     167

关键词:

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

状态定义 :

        可以用一个二维数组保持结果。二维数组有i行,两列。第一列代表持有股票的最大价值。第二列代表不持有股票的最大价值。

        dp[i][0]  第i天持有股票的最大价值(最小成本)

        dp[i][1] 第i天不持有股票的最大价值(最大收益)

转移方程:

        持有股票,说明买入股票,价值应该是负的。如果当天买入股票为-price[i]。但是可以不是当天买入的股票。可以是在价格最低点买入的股票。持有股票的最大价值,就是最低点买入的股票。所以持有股票最大价值为:dp[i][0]=max(-price[i],dp[i-1][0])。当天买入与之前买入的最大值

        不持有股票,说明是卖出股票,如果当天卖出股票,价值是dp[i][0]+price[i]。但是也可以不在当天卖出,可以在价格最高点的时候卖出。不持有股票时的最大价值就是在最高点卖出。所以不持有股票的最大值价值为:dp[i][1]=max(dp[i-1],dp[i][0]+price[i])。当天卖出的价值与之前卖出价值最大值。我的理解dp[i][0]+prices[i],当天卖出价值,为当天买入价值加上股票价值

初始化:

        第一天持有股票,只能是买入股票,因为没有之前的对比。dp[1][0]=-price[0]

        第一天不持有股票的最大价值,只能是将持有股票的卖出。dp[1][1]=dp[1][0]+price[0]=0

返回值:

        最后一天不持有股票的最大价值dp[price.size()][1]。

class Solution 
public:
    //用列为0的表示持有股票的最大价值,用列为1表示不持有股票的最大价值
    int maxProfit(vector<int>& prices) 
        int len=prices.size();
        vector<vector<int>> dp(len+1,vector<int>(2,0));
        //dp[0][0]=0;
        //dp[0][1]=0;
        //持有第一的股票,价值就是买入股票
        dp[1][0]=-prices[0];
        //卖出,价值为0
        dp[1][1]=0;
        //递推公式
        for(int i=2;i<=len;i++)
            dp[i][0]=max(dp[i-1][0],-prices[i-1]);
            dp[i][1]=max(dp[i-1][1],prices[i-1]+dp[i][0]);
        
        return dp[len][1];

    
;

122. 买卖股票的最佳时机 II (可多次买入卖出,但是买入前必须手里没有股票,卖出前手里只有一张股票)

给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

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

示例 1:

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

这题与上一题的解法如出一辙,但是由于可以多次买入卖出,转移方程有些不同。

转移方程:

        持有股票的最大价值变了:由于可以多次买入卖出,可能之前手里的价值不为0了,可能已经有收益。所以当天买入股票时的价值不是-price[i],而是dp[i][1]-price[i],收益减去买入股票的前。但是持有股票的最大价值也鄙视一定当天买入,也是要在收益最大时,在价值最低点买入。所以持有股票的最大价值为 dp[i][0] = max(dp[i][0]-prices[i],dp[i-1][0])。

class Solution 
public:
    int maxProfit(vector<int>& prices) 
        int len=prices.size();
        vector<vector<int>> dp(len+1,vector<int>(2,0));
        //初始化
        dp[1][0]=-prices[0];
        dp[1][1]=0;
        //转移方程
        for(int i=2;i<=len;i++)
            dp[i][0]=max(dp[i-1][1]-prices[i-1],dp[i-1][0]);
            dp[i][1]=max(dp[i][0]+prices[i-1],dp[i-1][1]);
        
        return dp[len][1];

    
;

123. 买卖股票的最佳时机 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 。

这题相比较于上两题有点难,难的点在于最多完成两笔交易。

意思是,可以以不交易,可以交易一次,可以交易两次

状态定义:

        我们可以定义5个状态:

        dp[i][0]:第i天不交易最大价值

        dp[i][1]:第i天第一次买入最大价值

        dp[i][2]:第i天第一次卖出最大价值

        dp[i][3]:第i天第二次买入最大价值

        dp[i][4]:第i天第二次卖出最大价值

dp横坐标为天数,纵坐标为5种状态

转移方程:

        有了上面两题,相信大家很容易得出转移方程:不如自己写一下

        dp[i][0]不交易始终为0

        dp[i][1]和dp[i][2]就像第一题一样

        dp[i][1]第一次买入,当前买入和之前买入的最大值。dp[i][0]=max(dp[i][0]-prices[i],dp[i-1][1])。      

        dp[i][2]第一次卖出,当前卖出价值和之前价值最大值。dp[i][1]=max(dp[i][1]+prices[i],dp[i-1][2])。

        dp[i][3]和dp[i][4]就和第二题一样

        dp[i][3]第二次买入,当前买入(已有利润)和之前买入的最大值。dp[i][0]=max(dp[i-1][2]-prices[i],dp[i-1][3])。      

        dp[i][4]第二次卖出,当前卖出价值和之前价值最大值。dp[i][1]=max(dp[i][3]+prices[i],dp[i-1][4])。

初始化:

        第一天你不操作:dp[1][0]=0

        第一天你买入:dp[1][1]=-prices[i-1]。

        第一天你卖出:dp[1][2]=dp[1][1]+prices[i-1]=0

        第二天你买入:dp[1][3]=dp[1][2]-prices[i-1]

        第二天你卖出:dp[1][4]=dp[1][3]+prices[i-1]=0

返回值:

        dp[prices.size()][4],最后不持有股票的最大价值。

这道题难的是状态定义,找出所有状态。

        

class Solution 
public:
    int maxProfit(vector<int>& prices) 
        int len=prices.size();
        vector<vector<int>> dp(len+1,vector<int>(5,0));
        //初始化
        dp[1][0]=0;
        dp[1][1]=-prices[0];
        dp[1][2]=0;
        dp[1][3]=-prices[0];
        dp[1][4]=0;
        //转移方程
        for(int i=2;i<=len;i++)
            dp[i][1]=max(-prices[i-1],dp[i-1][1]);
            dp[i][2]=max(dp[i-1][2],dp[i][1]+prices[i-1]);
            dp[i][3]=max(dp[i-1][2]-prices[i-1],dp[i-1][3]);
            dp[i][4]=max(dp[i][3]+prices[i-1],dp[i-1][4]);
        
        return dp[len][4];


    
;

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

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

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

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

示例 1:

输入:k = 2, prices = [2,4,1]
输出:2
解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。

这个题可以说是第3题的进阶版,将最多可以交易两次换成了最多可以交易k次。

解法还是和上一题一样,但是状态增加了。

状态定义:

        我们可以定义5个状态:

        dp[i][0]:第i天不交易最大价值

        dp[i][1]:第i天第一次买入最大价值

        dp[i][2]:第i天第一次卖出最大价值

        dp[i][3]:第i天第二次买入最大价值

        dp[i][4]:第i天第二次卖出最大价值

        dp[i][5]:第i天第三次买入最大价值

        dp[i][6]:第i天第三次卖出最大价值

        .......

        dp[i][2*k-1]:第i天第k次买入最大价值

        dp[i][2*k]:第i天第k次卖出最大价值

列为奇数下标买入,列为偶数小标卖出。

dp横坐标为天数,纵坐标为状态

转移方程:

        dp[i][0]不交易始终为0

        每一次的买入都是上一次(不是天)的利润减去这天股票篇的价格前一天的这一次买入价格最大值

dp[i][j]=max(dp[i][j-1]-prices[i],dp[i-1][j])

        每一次卖出都是当天剩余的钱加上当天股票价值上一天这一次的利润的最大值。

dp[i][j+1]=max(dp[i][j]+prices[i],dp[i-1][j+1])

初始化:

        第一天所有的买入都是-prices[0],数组上是下标为奇数的,值为-prices[0]。

返回值:

        dp[prices.size()][2*k],最后不持有股票的最大价值。

这道题难的是状态定义,找出所有状态。

class Solution 
public:
    int maxProfit(int k, vector<int>& prices) 
        int len=prices.size();
        if(len==0)
            return 0;
        
        vector<vector<int>> dp(len+1,vector<int>(2*k+1,0));
        //初始化,奇数下标,j从1开始,更新j,j+=2
        for(int j=1;j<2*k;j+=2)
            dp[1][j]=-prices[0];  
        
        //递推公式
        for(int i=2;i<=len;i++)
            //更新j,j+=2,不是j=2*j+1,少了5
            for(int j=1;j<2*k;j+=2)
                dp[i][j]=max(dp[i-1][j],dp[i][j-1]-prices[i-1]);
                dp[i][j+1]=max(dp[i-1][j+1],dp[i][j]+prices[i-1]);
            
        
        return dp[len][2*k];

    
;

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

给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

示例 1:

输入:prices = [1, 3, 2, 8, 4, 9], fee = 2
输出:8
解释:能够达到的最大利润:  
在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8

        这题和第二题的情况相同,只不过每次交易完毕后会要扣掉手续费。在代码中楼手续费在哪里体现呢?

        在不持有股票中体现,如果当天卖出,则需要交手续费即dp[i][0]+prices[i-1]-fee。则在不持有股票的最大值由两种情况得到:

        前一天不持有股票的价值与当天交易的价值即:dp[i][1]=max(dp[i-1][1],dp[i][0]+prices[i-1]-fee);

class Solution 
public:
    //状态和第二题一样
    int maxProfit(vector<int>& prices, int fee) 
        int len=prices.size();
        vector<vector<int>> dp(len+1,vector<int>(2,0));
        dp[1][0]=-prices[0];
        dp[1][1]=0;

        for(int i=2;i<=len;i++)
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i-1]);
            dp[i][1]=max(dp[i-1][1],dp[i][0]+prices[i-1]-fee);
        
        return dp[len][1];

    
;

309. 最佳买卖股票时机含冷冻期(一次交易后冷冻一天)

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:

输入: [1,2,3,0,2]
输出: 3 
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]

 这题也是在第二题基础上,添加了一个冷冻期的条件。难的地方在于将所有情况都列举出来。

状态定义:

        状态一:dp[i][0] :买入

        卖出包括两种情况

        状态二:dp[i][1]:之前已经卖出,已经度过冷冻期,但是不操作。

        状态三:dp[i][2]:当天卖出

        状态四:dp[i][3]:处于冷冻期

转移方程:

        买入:

                情况一:前一天为冷冻期  dp[i-1][3]-prices[i]。

                情况二:前一天不是冷冻期,但是也没有卖出(处于状态二),dp[i-1][1]-prices[i]。

                情况三:之前已经买入,dp[i-1][0]。

                dp[i][0]=max(dp[i-1][0],max(dp[i-1][3]-prices[i],dp[i-1][1]-prices[i])

        卖出:

        状态二:之前已经卖出,已经度过冷冻期,但是不操作(前一天是冷冻期)。

                情况一:前一天是冷冻期,dp[i-1][3]。

                情况二:还是没有操作,dp[i-1][2]。

               dp[i][1]=max(dp[i-1][3],dp[i-1][2])

        状态三:当天卖出

                情况一:当天卖出,dp[i][2]=dp[i][0]+prices[i]。

        冷冻期:

                情况一:前一天肯定是卖出:dp[i][3]=dp[i-1][2].

初始化:

        第一天买入dp[1][0]=-prices[i-1],

        第一天卖出dp[1][1]=0,dp[1][2]=0,第一天卖出价格收益也是0   

        冷冻期 dp[1][3]=0,第一天不存在冷冻期的情况

返回值 为卖出和冷冻期(可能请一天卖出最后一天是冷冻期)里最大的。

       max(dp[len][1],max(dp[len][3],dp[len][2]));

class Solution 
public:
    int maxProfit(vector<int>& prices) 
        int len=prices.size();
        vector<vector<int>> dp(len+1,vector<int>(4,0));
        //初始化
        dp[1][0]=-prices[0];
        dp[1][1]=0;
        dp[1][2]=0;
        dp[1][3]=0;

        // dp[i][0] :买入
        //dp[i][1]:之前已经卖出,已经度过冷冻期,但是不操作。
        //dp[i][2]:当天卖出
        //dp[i][3]:处于冷冻期
        for(int i=2;i<=len;i++)

            dp[i][0]=max(dp[i-1][0],max(dp[i-1][3]-prices[i-1],dp[i-1][1]-prices[i-1]));
            dp[i][1]=max(dp[i-1][1],dp[i-1][3]);
            dp[i][2]=dp[i][0]+prices[i-1];//当天一点是卖出,不需要于前一天比

            dp[i][3]=dp[i-1][2];//前一天一定是卖出
        
        return max(dp[len][1],max(dp[len][3],dp[len][2]));

    
;

动规-最大子矩阵(代码片段)

描述已知矩阵的大小定义为矩阵中所有元素的和。给定一个矩阵,你的任务是找到最大的非空(大小至少是1*1)子矩阵。比如,如下4*4的矩阵0-2-7092-62-41-41-180-2的最大子矩阵是92-41-18这个子矩阵的大小是15。输入输入是一个N*N... 查看详情

经典动态规划——0/1背包问题(二维数组动规,一维数组动规实现)(代码片段)

题目描述有为N件物品,它们的重量w分别是w1,w2,…,wn,它们的价值v分别是v1,v2,…,vn,每件物品数量有且仅有一个,现在给你个承重为M的背包,求背包里装入的物品具有的价值最大总和?输入描述:物品数量N... 查看详情

hdu4328cutthecake(动规:最大子矩形问题/悬线法)(代码片段)

题目链接:传送门题目大意:  给出N*M的字符矩阵(由字符B/R组成),求符合下图条件的子矩阵的最大周长。  1≤N,M≤1000。                     &n... 查看详情

动规-最长公共子上升序列(代码片段)

...列:存在1<=i1<i2<...<iN<=M,使得对所有1<=j<=N,均有S 查看详情

动规-最长公共子上升序列(代码片段)

...列:存在1<=i1<i2<...<iN<=M,使得对所有1<=j<=N,均有S 查看详情

树形动规专题(代码片段)

...了一个点能覆盖mid范围内的点,求要有几个点能全部覆盖所有的特殊点。想到消防局的设立:但是这道题目又不能那么做。考虑DP,设F[i]表示以i为根节点的子树中没有被覆盖的最远的点,g[i]表示以i为根的子树中距离i最近的已... 查看详情

动规(14)-三角形最佳路径问题(代码片段)

描述如下所示的由正整数数字构成的三角形:738810274445265从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的... 查看详情

动规(14)-三角形最佳路径问题(代码片段)

描述如下所示的由正整数数字构成的三角形:738810274445265从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的... 查看详情

动规(14)-三角形最佳路径问题(代码片段)

描述如下所示的由正整数数字构成的三角形:738810274445265从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的... 查看详情

python[风获取行业所有股票历史数据]#tags:风(代码片段)

查看详情

luogup4095[heoi2013]eden的新背包问题思维/动规(代码片段)

当时一直在想前缀和。。。多亏张队提醒。。。 从1到n背次包,保存每一个状态下的价值,就是不要把第一维压掉;再从n到1背一次,同样记住每种状态;然后询问时相当于是max(前缀+后缀),当然前缀后缀中间去掉了一个应... 查看详情

bttcoj问题e:维和部队线性动规(代码片段)

题目描述在2019国庆大阅兵仪式上,蓝色贝雷帽,荒漠迷彩服,维和部队方队阔步走来。中国是联合国安理会常任理事国中派出维和人员最多的国家。在联合国7个维和任务区,2500多名中国军人守护在最危险的地方&... 查看详情

一个方法团灭6道股票问题(代码片段)

作者:labuladong链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/solution/yi-ge-fang-fa-tuan-mie-6-dao-gu-piao-wen-ti-by-l-3/来源:力扣(LeetCode)著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 这6道股 查看详情

数据分析之dataframe基础操作巩固-股票分析(代码片段)

...以获取任意股票的历史交易数据pipinstalltushare输出该股票所有收盘比开盘上涨3%以上的日期。输出该股票所有开盘比前日收盘跌幅超过2%的日期。假如我从2010年1月1日开始,每月第一个交易日买入1手股票,每年最后一个交易日卖... 查看详情

rqnoj99配制魔药(动规)(代码片段)

...们每人配置一种魔药(不一定是一样的),Ron因为魔杖的问题,不能完成这个任务,他请Harry在魔药课上(自然是躲过了Snape 查看详情

动态规划基本思想(代码片段)

...且将其合理运用qwq。我们首先要了解的,便是综合难度在所有动规题里最为简单的线性动规了。线性动规既是一切动规的基础,同时也可以广泛解决生活中的各项问题——比如在我们所在的三维世界里,四维的时间就是不可逆式... 查看详情

动规(18)-并查集基础题——团伙(代码片段)

...我的朋友;   2、 我敌人的敌人是我的朋友;所有是朋友的人组成一个团伙。告诉你关于这N个人的M条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能 查看详情

动规(18)-并查集基础题——团伙(代码片段)

...我的朋友;   2、 我敌人的敌人是我的朋友;所有是朋友的人组成一个团伙。告诉你关于这N个人的M条信息,即某两个人是朋友,或者某两个人是敌人,请你编写一个程序,计算出这个城市最多可能 查看详情