代码随想录刷题day51|股票买卖(含冷冻期)&股票买卖(含手续费)


day51学习内容

day51主要内容

  • 股票买卖(含冷冻期)
  • 股票买卖(含手续费)

声明
本文思路和文字,引用自《代码随想录》


一、股票买卖–含冷冻期

309.原题链接

1.1、动态规划五部曲

1.1.1、 确定dp数组(dp table)以及下标的含义

  • 其中dp[i][j]表示在第i天结束时,处于某种特定状态j的最大利润。
  • 为了节省空间,这里采用了循环数组的技巧,即dp[i % 2][j],这意味着它只用一个2x4的数组来保存当前和前一天的状态,而不是用一个长度为len的数组。

状态定义
在给出的代码中,dp[i % 2][j]的四种状态具体定义如下:

  • [i][0]:持有股票(包括当天买入和之前就买入的情况)
  • [i][1]:经过冷冻期后,不持有股票且没有当天买入
  • [i][2]:在当天卖出股票
  • [i][3]:处于冷冻期(即在前一天卖出了股票)

1.1.2、确定递推公式

  1. 持有股票([i][0])的状态转移

    • 可以从前一天就持有股票的状态继续持有。
    • 可以在今天买入股票,这可以发生在前一天是冷冻期后或者是非冷冻期但不持股的状态之后。
  2. 非冷冻期且不持股([i][1])的状态转移

    • 如果前一天也是非冷冻期且不持股,则继续保持这个状态。
    • 如果前一天是冷冻期,那么今天自动转为非冷冻期且不持股。
  3. 卖出股票([i][2])的状态转移

    • 如果今天卖出股票,那么显然是从前一天持有股票的状态转变来的。
  4. 冷冻期([i][3])的状态转移

    • 冷冻期状态只能从前一天卖出股票的状态转变而来。

1.1.3、 dp数组如何初始化

dp数组是一个2x4的二维数组,用于存储在给定天数下,处于不同状态时的最大利润。由于使用了循环数组的技巧,实际上只需要存储当前和前一天的状态,因此第一维的大小为2。第二维的大小为4,对应四种不同的状态。

第0天的初始化

  • dp[0][0] = -prices[0]:这表示在第0天买入股票,所以利润是负的股票价格。这是因为持有股票意味着支付了股票价格的成本。
  • 对于其他的状态,在代码中没有显式初始化,但Java会默认将int数组的元素初始化为0。对于本问题,这意味着:
    • dp[0][1]默认为0,表示在第0天结束时,不持有股票且没有买入股票(在开始之前,我们就处于这个状态)的利润为0。
    • dp[0][2]在第0天是没有意义的,因为你不能在市场还未开始时就卖出股票。所以,虽然它被初始化为0,这个值在逻辑上不会被使用。
    • dp[0][3]表示处于冷冻期,同样在第0天是没有意义的,因为冷冻期是卖出股票后的状态,而在开始时还没有发生任何交易。

1.1.4、确定遍历顺序

从小到大遍历

1.1.5、输出结果

最后一天结束时,可能处于三种状态:非冷冻期且不持股、卖出股票、或是冷冻期。持有股票的状态不是最终的目标状态,因为题目的目的是最大化利润,而持有股票意味着尚未实现利润。因此,最终利润是这三种状态利润的最大值。

1.2、代码

class Solution {
    public int maxProfit(int[] prices) {
        int len = prices.length;
        int dp[][] = new int[2][4];
        dp[0][0] = -prices[0];

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

二、股票买卖–含手续费

714.原题链接

2.1、动态规划五部曲

2.1.1、 确定dp数组(dp table)以及下标的含义

  • dp:一个二维数组,用于存储动态规划的状态。
    • dp[i][0]表示第i天持有股票时的最大利润。
    • dp[i][1]表示第i天不持有股票时的最大利润。

2.1.2、确定递推公式

对于每一天i(从第1天开始迭代),动态规划的状态转移方程如下:

  • dp[i][0]:第i天持有股票的最大利润可以从以下两种情况中取较大值:
    • dp[i - 1][0]:前一天就持有股票,所以今天没有交易发生。
    • dp[i - 1][1] - prices[i]:前一天不持有股票,今天买入股票,需要支付prices[i]的购买成本。
  • dp[i][1]:第i天不持有股票的最大利润也可以从以下两种情况中取较大值:
    • dp[i - 1][1]:前一天就不持有股票,所以今天没有交易发生。
    • dp[i - 1][0] + prices[i] - fee:前一天持有股票,今天卖出股票,除了获得prices[i]的卖出收益外,还需要支付fee的手续费。

2.1.3、 dp数组如何初始化

  • dp[0][0] = -prices[0]:在第0天(即开始时)买入股票的情况,所以利润是负的股票价格。
  • 第0天不持有股票的利润默认为0(即dp[0][1]),因为在开始时没有股票可以卖出。

2.1.4、确定遍历顺序

从小到大遍历

2.1.5、输出结果

由于最后一天结束时持有股票的状态不一定比不持有股票的状态利润高,所以需要比较dp[len - 1][0]dp[len - 1][1],返回两者中的最大值作为最终的最大利润。

2.2、代码

public int maxProfit(int[] prices, int fee) {
    int len = prices.length;
    int[][] dp = new int[len][2];
    dp[0][0] = -prices[0];
    for (int i = 1; i < len; i++) {
        dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
        dp[i][1] = Math.max(dp[i - 1][0] + prices[i] - fee, dp[i - 1][1]);
    }
    return Math.max(dp[len - 1][0], dp[len - 1][1]);
}

总结

1.感想

  • 麻了。股票系列终于结束了

2.思维导图

本文思路引用自代码随想录,感谢代码随想录作者。

  • 21
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值