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

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

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

文章链接:买卖股票的最佳时机含冷冻期买卖股票的最佳时机含手续费股票系列总结

视频链接:买卖股票的最佳时机含冷冻期买卖股票的最佳时机含手续费

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

1.1 思路

  1. 本题是在122. 买卖股票的最佳时机 II的基础上加了个冷冻期,是可以多次买卖股票的,本题是在卖出股票后会有 1 天冷冻期即不能买了
  2. dp 数组及其下标的含义:dp[i][0] 是持有的状态,可以是当前买入或者前几天买入一直保持持有;dp[i][1] 保持卖出的状态(即冷冻期之后到买入的之前的状态,可以买入但不买的状态);dp[i][2] 具体卖出的状态(即冷冻期前卖出股票的状态);对于这里其实是把不持有的状态分成了 dp[i][1] 和 dp[i][2];dp[i][3] 即冷冻期,持续一天
  3. 递推公式: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],即前一天是刚卖出的状态
  4. dp 数组的初始化:dp[0][0]=-prices[i];dp[0][1] 这个状态本来就是不合理的状态,看看递推公式需要把它初始化成什么,在第 1 天变为持有的状态 dp[1][0]=Math.max(dp[0][0],Math.max(dp[0][3]-prices[0],dp[0][1]-prices[0]))可以看出应该把 dp[0][1] 初始化为 0;dp[0][2] 也是初始化为 0,同理是个不合理的状态,或者理解为当天买当天卖;dp[0][3]=0,同样是不合理的状态
  5. 遍历顺序:根据递推公式就是从前往后遍历。最终返回 Math.max(dp[prices.length-1][1],Math.max(dp[prices.length-1][2],dp[prices.length-1][3]))即将后面的三个状态取最大值
  6. 打印 dp 数组:用于 debug

1.2 代码

class Solution {
    public int maxProfit(int[] prices) {
        int len=prices.length-1;
        int[][] dp=new int[prices.length][4];
        dp[0][0]=-prices[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[len][1],Math.max(dp[len][2],dp[len][3]));
    }   
}

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

2.1 思路

  1. 本题是在122. 买卖股票的最佳时机 II的基础上在卖出的时候多加了手续费
  2. dp 数组及其下标的含义:dp[i][1] 是不持有股票的最大现金,dp[i][0] 是持有股票的最大现金
  3. 递推公式: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)即保持前一天不持有的状态,或者前一天持有然后卖出的状态再减去手续费
  4. dp 数组的初始化:dp[0][0]=-prices[0],dp[0][1]=0
  5. 遍历顺序:从前往后
  6. 打印 dp 数组:用于 debug

2.2 代码

/**
 * 卖出时支付手续费
 * @param prices
 * @param fee
 * @return
 */
public int maxProfit(int[] prices, int fee) {
    int len = prices.length;
    // 0 : 持股(买入)
    // 1 : 不持股(售出)
    // dp 定义第i天持股/不持股 所得最多现金
    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]);
}

3. 股票系列总结

3.1 121. 买卖股票的最佳时机

在数组中只能买卖一次,定义了两个状态,dp[i][0] 持有,dp[i][1] 不持有

如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来

  • 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
  • 第i天买入股票,所得现金就是买入今天的股票后所得现金即:-prices[i] 所以dp[i][0] = max(dp[i - 1][0], -prices[i]);

如果第i天不持有股票即dp[i][1], 也可以由两个状态推出来

  • 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
  • 第i天卖出股票,所得现金就是按照今天股票佳价格卖出后所得现金即:prices[i] + dp[i - 1][0] 所以dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);

3.2 122. 买卖股票的最佳时机 II

在数组中可以买卖多次了,和121. 买卖股票的最佳时机一样,也是定义两个状态,dp[i][0] 持有,dp[i][1] 不持有

如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来

  • 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
  • 第i天买入股票,所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即:dp[i - 1][1] - prices[i]

注意:在121. 买卖股票的最佳时机中,因为股票全程只能买卖一次,所以如果买入股票,那么第i天持有股票即dp[i][0]一定就是 -prices[i]。而本题,因为一只股票可以买卖多次,所以当第i天买入股票的时候,所持有的现金可能有之前买卖过的利润。

如果第i天不持有股票即dp[i][1], 也可以由两个状态推出来

  • 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
  • 第i天卖出股票,所得现金就是按照今天股票佳价格卖出后所得现金即:prices[i] + dp[i - 1][0] 所以dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);

3.3 123. 买卖股票的最佳时机 III

在数组中至多买卖两次,定义了五个状态,第 i 天 dp[i][0] 表示不操作,dp[i][1] 表示第 1 次持有,dp[i][2] 表示第 1 次不持有,dp[1][3] 表示第 2 次持有,dp[i][4] 表示第 2 次不持有

dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。

达到dp[i][1]状态,有两个具体操作:

  • 操作一:第i天买入股票了,那么dp[i][1] = dp[i-1][0] - prices[i]
  • 操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]
  • 即dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1]);

同理dp[i][2]也有两个操作:

  • 操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
  • 操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]
  • 所以dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])

同理可推出剩下状态部分:

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

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

3.4 188. 买卖股票的最佳时机 IV

在数组中至多买卖 k 次,和123. 买卖股票的最佳时机 III其实一样的,只是做了个抽象化,dp 数组的二维的下标通过一个变量来表示,方便至多买卖 k 次,表示对应的状态

使用二维数组 dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]

j的状态表示为:

  • 0 表示不操作
  • 1 第一次买入
  • 2 第一次卖出
  • 3 第二次买入
  • 4 第二次卖出

  • 除了0以外,偶数就是卖出,奇数就是买入

达到dp[i][1]状态,有两个具体操作:

  • 操作一:第i天买入股票了,那么dp[i][1] = dp[i - 1][0] - prices[i]
  • 操作二:第i天没有操作,而是沿用前一天买入的状态,即:dp[i][1] = dp[i - 1][1]
  • dp[i][1] = max(dp[i - 1][0] - prices[i], dp[i - 1][1]);

同理dp[i][2]也有两个操作:

  • 操作一:第i天卖出股票了,那么dp[i][2] = dp[i - 1][1] + prices[i]
  • 操作二:第i天没有操作,沿用前一天卖出股票的状态,即:dp[i][2] = dp[i - 1][2]
  • dp[i][2] = max(dp[i - 1][1] + prices[i], dp[i - 1][2])

同理可以类比剩下的状态

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

含有冷冻期,这里其实也算是两个状态 dp[i][0] 持有,dp[i][1] 不持有,但把不持有分成 3 个状态了,变为 dp[i][1] 保持卖出的状态,dp[i][2] 具体卖出的状态,dp[i][3] 冷冻期

dp[i][j]:第i天状态为j,所剩的最多现金为dp[i][j]。

  • 状态一:买入股票状态(今天买入股票,或者是之前就买入了股票然后没有操作)
  • 卖出股票状态,这里就有两种卖出股票状态
  • 状态二:两天前就卖出了股票,度过了冷冻期,一直没操作,今天保持卖出股票状态
  • 状态三:今天卖出了股票
  • 状态四:今天为冷冻期状态,但冷冻期状态不可持续,只有一天!

达到买入股票状态(状态一)即:dp[i][0],有两个具体操作:

  • 操作一:前一天就是持有股票状态(状态一),dp[i][0] = dp[i - 1][0]
  • 操作二:今天买入了,有两种情况
  • 前一天是冷冻期(状态四),dp[i - 1][3] - prices[i]
  • 前一天是保持卖出股票状态(状态二),dp[i - 1][1] - prices[i]
    所以操作二取最大值,即:max(dp[i - 1][3], dp[i - 1][1]) - prices[i]
    那么dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i]);

达到保持卖出股票状态(状态二)即:dp[i][1],有两个具体操作:

  • 操作一:前一天就是状态二
  • 操作二:前一天是冷冻期(状态四)
    dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);

达到今天就卖出股票状态(状态三),即:dp[i][2] ,只有一个操作:

  • 操作一:昨天一定是买入股票状态(状态一),今天卖出
    即:dp[i][2] = dp[i - 1][0] + prices[i];

达到冷冻期状态(状态四),即:dp[i][3],只有一个操作:

  • 操作一:昨天卖出了股票(状态三)
    dp[i][3] = dp[i - 1][2];

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

就是在122. 买卖股票的最佳时机 II的基础上卖出的时候多了手续费

dp数组的含义:

dp[i][0] 表示第i天持有股票所省最多现金。 dp[i][1] 表示第i天不持有股票所得最多现金

如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来

  • 第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
  • 第i天买入股票,所得现金就是昨天不持有股票的所得现金减去 今天的股票价格 即:dp[i - 1][1] - prices[i]
    所以:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);

如果第i天不持有股票即dp[i][1]的情况, 依然可以由两个状态推出来

  • 第i-1天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]
  • 第i天卖出股票,所得现金就是按照今天股票价格卖出后所得现金,注意这里需要有手续费了即:dp[i - 1][0] + prices[i] - fee
    所以:dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);
相关文章
|
4天前
|
机器学习/深度学习 存储 算法
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
近端策略优化(PPO)是深度强化学习中高效的策略优化方法,广泛应用于大语言模型的RLHF训练。PPO通过引入策略更新约束机制,平衡了更新幅度,提升了训练稳定性。其核心思想是在优势演员-评论家方法的基础上,采用裁剪和非裁剪项组成的替代目标函数,限制策略比率在[1-ϵ, 1+ϵ]区间内,防止过大的策略更新。本文详细探讨了PPO的基本原理、损失函数设计及PyTorch实现流程,提供了完整的代码示例。
104 10
近端策略优化(PPO)算法的理论基础与PyTorch代码详解
|
2月前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
3月前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
99 1
|
3月前
|
存储 缓存 算法
通过优化算法和代码结构来提升易语言程序的执行效率
通过优化算法和代码结构来提升易语言程序的执行效率
|
3月前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
2天前
|
算法 数据安全/隐私保护 计算机视觉
基于FPGA的图像双线性插值算法verilog实现,包括tb测试文件和MATLAB辅助验证
本项目展示了256×256图像通过双线性插值放大至512×512的效果,无水印展示。使用Matlab 2022a和Vivado 2019.2开发,提供完整代码及详细中文注释、操作视频。核心程序实现图像缩放,并在Matlab中验证效果。双线性插值算法通过FPGA高效实现图像缩放,确保质量。
|
1月前
|
算法 数据安全/隐私保护 计算机视觉
基于Retinex算法的图像去雾matlab仿真
本项目展示了基于Retinex算法的图像去雾技术。完整程序运行效果无水印,使用Matlab2022a开发。核心代码包含详细中文注释和操作步骤视频。Retinex理论由Edwin Land提出,旨在分离图像的光照和反射分量,增强图像对比度、颜色和细节,尤其在雾天条件下表现优异,有效解决图像去雾问题。
|
1月前
|
算法 数据可视化 安全
基于DWA优化算法的机器人路径规划matlab仿真
本项目基于DWA优化算法实现机器人路径规划的MATLAB仿真,适用于动态环境下的自主导航。使用MATLAB2022A版本运行,展示路径规划和预测结果。核心代码通过散点图和轨迹图可视化路径点及预测路径。DWA算法通过定义速度空间、采样候选动作并评估其优劣(目标方向性、障碍物距离、速度一致性),实时调整机器人运动参数,确保安全避障并接近目标。
147 68
|
1月前
|
算法 数据安全/隐私保护
室内障碍物射线追踪算法matlab模拟仿真
### 简介 本项目展示了室内障碍物射线追踪算法在无线通信中的应用。通过Matlab 2022a实现,包含完整程序运行效果(无水印),支持增加发射点和室内墙壁设置。核心代码配有详细中文注释及操作视频。该算法基于几何光学原理,模拟信号在复杂室内环境中的传播路径与强度,涵盖场景建模、射线发射、传播及接收点场强计算等步骤,为无线网络规划提供重要依据。
|
3天前
|
传感器 算法 物联网
基于粒子群算法的网络最优节点部署优化matlab仿真
本项目基于粒子群优化(PSO)算法,实现WSN网络节点的最优部署,以最大化节点覆盖范围。使用MATLAB2022A进行开发与测试,展示了优化后的节点分布及其覆盖范围。核心代码通过定义目标函数和约束条件,利用PSO算法迭代搜索最佳节点位置,并绘制优化结果图。PSO算法灵感源于鸟群觅食行为,适用于连续和离散空间的优化问题,在通信网络、物联网等领域有广泛应用。该算法通过模拟粒子群体智慧,高效逼近最优解,提升网络性能。