代码随想录算法训练营第五十一天|309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费、总结

文章讲述了使用动态规划方法求解股票买卖问题,考虑了持有、卖出、冷冻期和手续费的情况。通过dp数组表示不同状态下的最大现金,详细解释了状态转移方程和初始化过程,以及遍历顺序。

代码随想录 (programmercarl.com)

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

可以多次交易买卖股票

1.dp数组及下标的含义

dp[i][0]:持有股票的状态,拥有的最大现金数

dp[i][1]:保持卖出股票的状态

dp[i][2]:卖出股票的状态(此时表示第i天就是卖出了股票,与之前的不持有股票状态有所区别)

dp[i][3]:冷冻期,持续一天

2.递推公式

对于以上四种状态,分别写出其对应的递推公式:

1)保持持股:

dp[i][0] = max(dp[i - 1][0], dp[i - 1][3] - prices[i], dp[i - 1][1] - prices[i]);

维持原样和买入股票两种类型二选一,避免连续两次买入股票的操作(因为不是max)

2)保持卖出股(表示在当天没有卖出操作,只是保持卖出状态,即经历过冷冻期之后一直没有操作):

dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);

3)卖出股票(就表示在当天卖出):

dp[i][2] = dp[i - 1][0] + prices[i]; 

4)冷冻期:

dp[i][3] = dp[i - 1][2]; 

3.初始化

dp[0][0] = - prices[0];

此处初始化的时候,其实dp[0][1],dp[0][2],dp[0][3]在第0天的时候都是非法状态,所以按照定义无法合理化初始值,可以从递推公式入手。

比如当i = 1时,dp[1][0] = dp[0][1] - prices[1],其中dp[1][0]表示的是第1天持股状态下的最大现金,应当为- prices[1],所以根据递推公式可知,dp[0][1] = 0。

其余也可以利用i = 1代入到递推公式之后进行判断。

dp[1][1] = dp[0][3],表示含义为第1天保持卖出状态的最大现金,相当于在第1天当天买入再卖出,即dp[1][1] = 0,所以dp[0][3] = 0。

dp[1][3] = dp[0][2],表示含义为第1天冷冻期状态下的最大现金,此时和上面分析一样,可以理解为当天就进行了买入卖出的操作,dp[1][3] =  0,所以dp[0][2] = 0。

4.遍历顺序

从前往后遍历

class Solution {
    public int maxProfit(int[] prices) {
        if(prices == null | prices.length == 0){
            return 0;
        }
        int[][] dp = new int[prices.length][4];
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = 0;
        dp[0][3] = 0;
        for (int i = 1; i < prices.length; i++) {
            dp[i][0] = Math.max(dp[i - 1][0], Math.max(dp[i - 1][3] - prices[i], dp[i - 1][1] - prices[i]));
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][3]);
            dp[i][2] = dp[i - 1][0] + prices[i];
            dp[i][3] = dp[i - 1][2];
        }
        return Math.max(dp[prices.length - 1][1], Math.max(dp[prices.length - 1][2], dp[prices.length - 1][3]));
    }
}

5.打印dp数组

714.买卖股票的最佳时机含手续费

可以多次交易买卖股票

和LC122代码几乎一样,需要注意此题的手续费说明【注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。】

所以手续费只需要在卖出股票的时候交一次即可!

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

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Buuuleven.(程序媛

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

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

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

打赏作者

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

抵扣说明:

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

余额充值