20200714:动态规划复习day05

动态规划复习day05

今天继续说股票问题三

题目: 买卖股票的最佳时机Ⅲ

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cJZruSgv-1594733150077)(C:\Users\Mr IMMUNIZE\AppData\Roaming\Typora\typora-user-images\image-20200714201753992.png)]

解题思路

同理,我们还是按照老样子走。

  1. 先判断状态和选择
    • 状态:今天第i天,我手里是否有股票,以及我卖出过几次股票。
    • 选择:我要么卖,要么买。
  2. 再定义dp数组
    • dp数组的定义根据上面的来看,状态有3个值,我们可以使用三维dp数组来实现,dp [i] [j] [k]表示这三个状态值。j表示是否持有股票,也就是只有两种状态,j可取0或者1。k的状态表示卖出过几次股票,因为我们只允许卖2次,因此k可取0,1,2三个值。这样也就确定了dp数组的含义:第i天持股状态为j,卖出股票数目为k时我能得到的最大利润。
  3. 最后确定dp状态转移方程
    • j = 0 ,手里没股票的情况
      • dp [i] [0] [0] 表示 k = 0 我也没卖出过股票,所以dp [i] [0] [0] = dp [i-1] [0] [0]
      • dp [i] [0] [1] 表示 k = 1我在今天之前卖出过1支股票,因此我的收入取决于我啥时候卖出的股票,即要么我昨天之前就已经卖出了这支股票,要么我今天卖的,取决于这二者中较大的一个。即
        • dp [i] [0] [1] = max(dp [i-1] [0] [1],dp [i-1] [1] [0] + prices[i])
      • dp [i] [0] [2] 表示 k = 2,我要么今天之前已经卖出了两股了,要么今天之前我卖了一股,今天我再卖一股
        • dp [i] [0] [2] = max(dp [i-1] [0] [1] + prices[i], dp [i-1] [0] [2])
    • j = 1 手里有股票的情况
      • 要么昨天我手里就有股票,要么我昨天手里没有,我今天买了一支。
        • dp [i] [1] [0] = max(dp [i-1] [1] [0],dp [i-1] [0] [0]-prices[i]);
      • 卖出过一次,然后又买了第二支,还没卖出去,那么我要么前一天就卖出过一次,但我手里没股票,然后今天又买了;要么,我前一天就卖出过一次,但我手里有,我今天啥也没干。
        • dp [i] [1] [1] = max(dp [i-1] [1] [1],dp [i-1] [0] [1]-prices[i]);
  4. 今天别忘了base case
    1. 第一天我手里就有股票,那么我不存在卖出股票数目k只能为0,dp [0] [1] [,0] = 0-prices[0]
    2. 第一天我手里没得股票,那么我第一天没买,dp [0] [0] [0] = 0;
  5. 我们的目标
    1. 求的是最后一天结束的时候我手里没股票的时候卖出过1次或者2次的最大利润。注意这个描述
    2. 即max(dp [len - 1] [0] [1] ,dp [len - 1] [0] [2])

到此我们分析完成,进行代码实现即可

代码实现

class Solution {
    public int maxProfit(int[] prices) {
        int len = prices.length;
        if (len <= 1) {
            return 0;
        }
        int[][][] dp = new int[len][2][3];

        // base case
        dp[0][1][0] = 0-prices[0];
        dp[0][1][1] = 0-prices[0];
        dp[0][1][2] = 0-prices[0];
        dp[0][0][0] = 0;
        // dp[0][0][1] = 0;
        // dp[0][0][2] = 0;

        // dp转移
        for (int i = 1; i < len ; i++) {
            dp[i][0][0] = 0;
            dp[i][0][1] = Math.max(dp[i - 1][0][1],dp[i - 1][1][0] + prices[i]);
            dp[i][0][2] = Math.max(dp[i - 1][0][2],dp[i - 1][1][1] + prices[i]);
            dp[i][1][0] = Math.max(dp[i - 1][1][0],dp[i - 1][0][0] - prices[i]);
            dp[i][1][1] = Math.max(dp[i - 1][1][1],dp[i - 1][0][1] - prices[i]);
            // dp[i][1][2] = 0;
        }
        return Math.max(dp[len - 1][0][1],dp[len - 1][0][2]);
    }
}

最后注意dp [0] [1] [1-2]这不存在的部分也要初始化出来的,而dp [0] [0] [k],k取1或者2的部分本来默认就是0,可以不写在basecase里,以及最后的dp [i] [1] [2]也是没意义的,可以不初始化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IMMUNIZE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值