其他分享
首页 > 其他分享> > 股票问题

股票问题

作者:互联网

股票问题一直是动态规划常见场景之一,其中的奇淫技巧也不在少数,而本文旨在阐述股票买卖问题的动态规划通用解法,虽然在运行速率上比针对题目的专门题解,但几乎能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