股票问题
作者:互联网
股票问题一直是动态规划常见场景之一,其中的奇淫技巧也不在少数,而本文旨在阐述股票买卖问题的动态规划通用解法,虽然在运行速率上比针对题目的专门题解,但几乎能AC所有的股票买卖问题。
首先,股票买卖涉及到的题目有很多,但框架类似,基本都是给定一个数组里面包含着每天的股票价格,给定一个参数K,限制最多的交易次数。有时也会加入一些买卖后的冷静时间或者手续费之类的附加条件,但总体基本不变。
股票问题的共性在于:
每天都有三种「选择」:买入、卖出、无操作,我们用 buy
, sell
, rest
表示这三种选择。但问题是,并不是每天都可以任意选择这三种选择的,因为 sell
必须在 buy
之后,buy
必须在 sell
之后。那么 rest
操作还应该分两种状态,一种是 buy
之后的 rest
(持有了股票),一种是 sell
之后的 rest
(没有持有股票)。而且别忘了,我们还有交易次数 k
的限制,就是说你 buy
还只能在 k > 0
的前提下操作。
所以我们可以用一个三维数组,表示出每一天的状态。第一维度指的是第几天,第二维度为目前还最多能交易的次数,第三维度为目前是否持有股票。比如说 dp[3][2][1]
的含义就是:今天是第三天,我现在手上持有着股票,至今最多进行 2 次交易。再比如 dp[2][3][0]
的含义:今天是第二天,我现在手上没有持有股票,至今最多进行 3 次交易。
而我们最终需要求得的是dp[n-1][k][0],也就是最后一天,能在最多交易k次,且手中不含有股票的情况下的最大利润。
状态转移方程为:
dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]) // max( 选择 rest , 选择 sell )
对于第i天,我手中未持有的情况可能性有两种:1.我前一天手中就未持有股票。2.前一天持有,但是我今天把股票卖了。
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]) // max( 选择 rest , 选择 buy )
对于第i天,我手中持有股票的情况同样分两种:1.前一天手中持有。2.前一天未持有,但我今天买入了。
在这里注意k-1,意味着在我买入的时候是需要消耗k的,因为我今天需要买入,所以昨天最多只能交易k-1次。(交易总数最多为k).
当状态转移方程完成后,我们就可以写出大概的框架了。
class Solution { public int maxProfit( int[] prices) { int k=xx; //根据题目要求做的k次交易,如果不限制次数,就把k去掉,之后k对应维度也去掉。 int[][][] dp = new int[prices.length+1][k+1][2]; //为了方便我们使天数从1开始,所以我们数组范围定义为prices.length+1. for(int i=0;i<=k;i++){ dp[0][i][0]=0; dp[0][i][1]=Integer.MIN_VALUE; // 最初时也就是第0天,如果手上没股票,那就是0,如果还未开始就持有股票,这是不现实的所以用MIN_VALUE。 } for(int i=1;i<=prices.length;i++){ //从第一天开始遍历 for(int j=1;j<=k;j++){ // 从k大于1开始遍历,因为可能会疑惑k=0时的情况,但java对数组默认初始值为0,因此类似于dp[2][0][0]不需要再处理 dp[i][j][0]=Math.max(dp[i-1][j][0], dp[i-1][j][1]+prices[i-1]);2 dp[i][j][1]=Math.max(dp[i-1][j][1], dp[i-1][j-1][0]-prices[i-1]); } } return dp[prices.length][k][0]; } }
当写出框架后,我们就可以对股票问题进行一般性的求解了。
标签:buy,int,股票,rest,问题,持有,dp 来源: https://www.cnblogs.com/xxsdbk/p/15174494.html