买卖股票的最佳时机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]});}
};