Java刷题笔记10: 最佳买卖股票时机含冷冻期

最佳买卖股票时机含冷冻期

题目描述

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

  • 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 卖出股票后,

  • 你无法在第二天买入股票 (即冷冻期为 1 天)。

示例

输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]

题目链接

动态规划

此题中第i天的最大收益,与之前所做的操作息息相关。它必定包含最优子结构,以及重叠子问题。想要计算出第i天的最大收益,那么就要在第i-1天时也能计算出最大收益。
动态规划最重要的一步就是写出状态转移方程。在此题中看似有四种状态

  • 状态1:不处于冷却期,且持有一张股票
  • 状态2:不处于冷却期,且不持有股票
  • 状态3:处于冷却期,且不持有股票
  • 状态4:处于冷却期,且持有一张股票

实际上,仔细查看题目就可以知道,只有当卖出股票后才会进入冷却期,也就是说处于冷却期时,一定不持有股票。那么状态之间如何转换呢。显然,状态1可以由状态1转移,这种情况在操作上表现为,不买入也不卖出。状态1也可由状态2转移,这意味着买入了当天的股票。状态2可由状态2以及状态3转移,这两种转移方式都表示当天无买入或卖出的操作。状态3可由状态1转移,意味着当天卖出了股票。我们可以用一个包含三个一维数组的二维数组来储存这三种状态。

public int maxProfit(int[] prices) {
        if (prices == null || prices.length < 1) {
            return 0;
        }
        //max(dp[0][i],dp[1][i],dp[2][i])表示第i天后最大收益
        int dp[][] = new int[3][prices.length];
//        dp[0][i] 状态1:不在冷却期,持有股票
//        dp[1][i] 状态2:不在冷却期,不持有股票
//        dp[2][i] 状态3:冷却期
        dp[0][0] = -prices[0];
        for (int i = 1; i < prices.length; i++) {
            //不在冷却期且持有股票,可从状态1转移(无操作),也可以从状态2转移(买入)
            dp[0][i] = Math.max(dp[0][i - 1], dp[1][i - 1] - prices[i]);
            //状态2可由状态2、状态3转移(两种转移方式均无操作)
            dp[1][i] = Math.max(dp[1][i - 1], dp[2][i - 1]);
            //状态3可由状态1转移(卖出)
            dp[2][i] = dp[0][i - 1] + prices[i];
        }
        return Math.max(dp[0][prices.length - 1], Math.max(dp[1][prices.length - 1], dp[2][prices.length - 1]));
}

时间复杂度与空间复杂度均为O(n)。不过以上代码的空间复杂度还可以优化。因为第i天的最大收益只与dp[0][i-1],dp[1][i-1],dp[2][i-1]这三个数有关。若想进一步优化空间则将这三个数用变量储存即可。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值