买卖股票的最佳时机III和IV

买卖股票的最佳时机III

问题描述与解题思路

leetcode 123
在这里插入图片描述

确定本题的状态表示

f[i][j] 表示:第 i 天结束之后,完成了 j 次交易,此时处于 “买入” 状态下的,最大利润
g[i][j] 表示:第 i 天结束之后,完成了 j 次交易,此时处于 “卖出” 状态下的,最大利润

确定本题的状态转移方程

状态转移方程依然需要通过分类讨论才能确定
如果头天结束之后处于卖出的状态,第二天有没有可能继续处于卖出状态呢?答案是可以。第二天啥都不干就行了。如果头天结束之后处于卖出的状态,第二天有没有可能处于买入状态呢?当然也可以,第二天买入一只股票即可,但是这有个前提条件,那就是买入股票之前,我的交易次数不能达到两次。如果达到了两次,那么即使头天结束时处于卖出的状态,第二天也不能买入了。
如果头天结束之后处于买入的状态,那么第二天有没有可能处于买入状态呢?答案是没问题,继续第二天啥也不干就行了
如果头天结束之后处于买入的状态,那么第二天有没有可能处于卖出状态呢?答案是没问题,卖出手里的那支股票就行

然后我们就可以根据上面的分析画出状态转移图。
在这里插入图片描述
然后我们就可以列出状态转移方程如下。大家看到这个状态转移方程的时候可能会有一些疑惑,因为我这个题目它的一个特殊条件限制就是:股票交易两次之后就不能再交易了。但是你这个状态方程并没有体现出这个限制特点呀?其实已经体现出来了,因为我们创建数组的时候儿就规定了。这个二维数组的列数为三。我们就通过这个来去规定:交易次数不能超过两次。
在这里插入图片描述

初始化

这个题的初始化还是比较有讲究的。因为我以前初始化的时候都是默认为零嘛。但是这个题就不行,如果按这样做的话是ak不了的。那我们就来分析分析为什么不能初始化为0
首先对于f[0][0],它的意义是第一天结束的时候交易量为0,且处于买入状态时的最大利润,其实只有一种情况能够满足我上面的条件,那就是我买入当天的股票。因此f[0][0]=-prices[0]。这时候某些想不通的人可能会问。你求的不是最大利润吗?既然买入之后利润为负,那我不买入,我取利润为零,不行吗?那你就忽略了一个条件,那就是f[0][0]代表的含义就是买入状态下,也就是手里持有一只股票的状态下能获得的最大利润。也就是说买入股票是前提,必须买。
然后g[0][0]这个没啥好讲的,对应的情况就是第一天啥都没干,初始化为0就行了。
然后对于g[0][1],它的意义是第一天结束的时候,交易量为一且处于卖出状态时的最大利润,这个时候有的人就会讲,这种状态是不可能达到的嘛,我以前遇到这样的情况都是直接把它设成零。但在这个题中其实设成0是不行的,我给你举个例子,虽然f[0][1]没有任何意义,但g[1][1]就有意义了吧,他的物理意义就是第二天结束的时候,达成一笔交易。且处于卖出状态时的最大利润。我们都知道要满足上面的条件。只有一种情况。那就是第一天买入,第二天卖出。那么实际上g[1][1]就是f[0][0]+prices[1],但我在算g[1][1]的时候,按照我们的递推公式,g[1][1]=max(g[0][1],f[0][0]+prices[1]),假如说f[0][0]+prices[1]最后算出来小于0,而你定义g[0][1]等于0,你这一比,g[1][1]不就不等于f[0][0]+prices[1],而等于0了吗,这就不对了!为了解决这种情况,我们就要让g[0][1]这种没有实际意义的取值尽可能地小
在这里插入图片描述
取值尽可能的小,那么大家第一反应可能就会是INT_MIN,但实际上我们也是不推荐取这个值的,因为如果在程序运行过程中这个值减一个1,编译器就会报错,有的编译器会将这个结果转化成一个非常大的正值。这都是我们预料不到的情况,最后排障的时候就会很难排查。为了避免出现这些溢出问题,我们一般取int类型的最大值,都会取0x3f3f3f3f这样一个值,最小值就取负的0x3f3f3f3f,也就是0xc0c0c0c1,这样就不会出现上面的问题。

在这里插入图片描述

代码实现

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n=prices.size();
        // f[i]表示第i天结束处于买入状态(手里持有一只股票)的最大利润
        // g[i]表示第i天结束处于卖出状态(手里没有股票)的最大利润
        vector<vector<int>> f(n,vector<int>(3,0));
        vector<vector<int>> g(n,vector<int>(3,0));
        f[0][0]=-prices[0];
        g[0][0]=0;
        f[0][1]=0xc0c0c0c1;
        f[0][2]=0xc0c0c0c1;
        g[0][1]=0xc0c0c0c1;
        g[0][2]=0xc0c0c0c1;

        for(int i=1;i<n;i++){
            for(int j=0;j<3;j++){
                f[i][j]=max(f[i-1][j],g[i-1][j]-prices[i]);
                if(j==0) g[i][j]=g[i-1][j];
                else g[i][j]=max(g[i-1][j],f[i-1][j-1]+prices[i]);
            }
        }
        return max({f[n-1][0],f[n-1][1],f[n-1][2],g[n-1][0],g[n-1][1],g[n-1][2]});
    }
};

买卖股票的最佳时机IV

题目链接
在这里插入图片描述

这题的状态转移方程和初始化的思路都是和三是一样一样的。我们只需要将三的代码按4的要求稍加改动。就可以得到解决这个问题的代码。因此不再过多解释。

状态转移方程

在这里插入图片描述

代码实现

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n=prices.size();
        const int INF=0x3f3f3f3f;
        vector<vector<int>> f(n,vector<int>(k+1,-INF));
        vector<vector<int>> g(n,vector<int>(k+1,-INF));
        f[0][0]=-prices[0];
        g[0][0]=0;
        for(int i=1;i<n;i++){
            for(int j=0;j<k+1;j++){
                f[i][j]=max(f[i-1][j],g[i-1][j]-prices[i]);
                if(j==0) g[i][j]=g[i-1][j];
                else g[i][j]=max(g[i-1][j],f[i-1][j-1]+prices[i]);
            }
        }
        int ret=0;
        for(int i=0;i<=k;i++){
            if(g[n-1][i]>ret)
            ret=g[n-1][i];
        }
        return ret;
    }
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值