news 2026/4/23 17:11:37

代码随想录算法训练营第三十六天:买卖股票的最佳时机IV,买卖股票的最佳时机含冷冻期,买卖股票的最佳时机含手续费

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
代码随想录算法训练营第三十六天:买卖股票的最佳时机IV,买卖股票的最佳时机含冷冻期,买卖股票的最佳时机含手续费

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

文章讲解/视频讲解

题目描述:

给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。

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

  • 示例 1:

  • 输入:k = 2, prices = [2,4,1]

  • 输出:2 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2。

  • 示例 2:

  • 输入:k = 2, prices = [3,2,6,5,0,3]

  • 输出:7 解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。

提示:

  • 0 <= k <= 100
  • 0 <= prices.length <= 1000
  • 0 <= prices[i] <= 1000

思路:

本题作为昨天III的进阶版,算得上是名副其实的hard了,昨天的III是说最多可以买卖2次,也就是限定在了可以买卖0次,1次,2次。但是本题给的是最多可以买卖k次,这就要稍微发散一下思维了。

1.确定dp数组及其下标含义:dp[i][j] :第i天的状态为j,所剩下的最大现金是dp[i][j]

j的状态表示为:

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

规律其实很明显了,除了0以外,只要是j为单数就是买入,j为偶数就是卖出。因为题目规定最多交易k次,所以范围定为 2 * k + 1,也就是k(买入) + k(卖出) + 1(初始)= 2k + 1

2.确定递推公式:dp[i][j]只能通过两种情况推出来,要么前一天就已经是目前的状态了(dp[i -1][j])。

要么前一天与今天的状态相反:比如前一天没持有,今天持有(把股票买入了),那么我们手里的现金就得减去买股票的钱,也就是dp[i -1][j -1] - price[i]。

还有可能是前一天持有,今天不持有了(股票抛掉了),那么我们手里的现金就多出来了卖出股票的钱,即dp[i -1][j -1] + price[i]。

我们很容易就能发现这两个公式唯一的差别就是加减号上,再仔细一想,只有当j是奇数(今天买入)时,我们要减,当j是偶数是(今天卖出)时,我们就加。那我们就直接用一个Math.pow( -1 , j),计算-1的j次方,并且用计算出来的结果去乘price[i],直接就能用一行代码搞定加减号的问题,如下:

dp[i - 1][j - 1] + Math.pow(-1, j) * prices[i]

最后我们只需要比较两种情况谁大就行了,所以递推公式完整代码如下:

dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + Math.pow(-1, j) * prices[i])

3.dp数组的初始化:毋庸置疑还是第0天要初始化,这个昨天就有一步一步递推了,j为单数时全部初始化为-price[0](容易错写成-price[i]),偶数直接全赋值为0即可。

4.确定遍历顺序

从递归公式其实已经可以看出,一定是从前向后遍历,因为dp[i],依靠dp[i - 1]的数值。

5.举例推导dp数组

以输入[1,2,3,4,5],k=2为例。

最后一次卖出,一定是利润最大的,dp[prices.size() - 1][2 * k]即红色部分就是最后求解。

代码示例:

function maxProfit(k: number, prices: number[]): number { const length: number = prices.length if (length === 0) return 0 const dp: number[][] = new Array(length).fill(0).map(_ => new Array(k * 2 + 1).fill(0)) for (let i = 1; i <= k; i++) { dp[0][i * 2 - 1] = -prices[0] } for (let i = 1; i < length; i++) { for (let j = 1; j < 2 * k + 1; j++) { dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - 1] + Math.pow(-1, j) * prices[i]) } } return dp[length - 1][2 * k] };

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

文章讲解/视频讲解

题目描述:

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

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

  • 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
  • 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

示例:

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

思路:
本题比较阴间的点在于,加入了一个冷冻期那就得区分成四种状态:1.持有股票状态 2.保持卖出股票的状态 3.今天卖出股票 4.今天为冷冻期 状态2和状态4在逻辑上是可以合并的,但是放代码里就会变得极其混乱,所以还是单独拎出来了。

1.确定dp数组及其下标含义:dp[i][j],第i天状态为j,所剩的最多现金为dp[i][j],j的状态为:

  • 0:状态一
  • 1:状态二
  • 2:状态三
  • 3:状态四

注意这里都是持有,并非一定买入,保持买入或卖出的意思是可能前几天就买入或者卖出了,然后一直没有操作

2.确定递推公式:这是本题的主要难点,需要一个状态一个状态分析,总共四行代码:

状态一(保持买入):要么前一天就已经买入了。要么今天买入,这又能分两种情况了,前一天是冷却期(状态四),前一天是保持卖出的状态(状态二)

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

状态二(保持卖出):可以是前一天就已经是卖出状态了,也可以是前一天处于冷冻期(状态四)

所以dp[i][1] = 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];

3.dp数组如何初始化:还是主要讨论第0天怎么初始化,首先dp[0][0](持有股票状态)肯定等于-price[0],这是毋庸置疑的,只能是当天买入股票。剩下的三种状态只能初始化为0,如果初始化为其他数值,第一天买入股票后,手里剩的现金数量就对不上账了,可以自己带进去试试看。

4.确定遍历顺序

从递归公式上可以看出,dp[i] 依赖于 dp[i-1],所以是从前向后遍历。

5.举例推导dp数组

以 [1,2,3,0,2] 为例,dp数组如下:

最后结果是取 状态二,状态三,和状态四的最大值,更容易就会把状态四忘了,状态四是冷冻期,最后一天如果是冷冻期也可能是最大值。

代码示例:

function maxProfit(prices: number[]): number { const length: number = prices.length if (length === 0) return 0 const dp: number[][] = new Array(length).fill(0).map(_ => []) dp[0][0] = -prices[0] dp[0][1] = dp[0][2] = dp[0][3] = 0 for (let i = 1; i < 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] } const lastrE1: number[] = dp[length - 1] return Math.max(lastrE1[1], lastrE1[2], lastrE1[3]) };

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

文章讲解/视频讲解

题目描述:

给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

示例 1:

  • 输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
  • 输出: 8

解释: 能够达到的最大利润:

  • 在此处买入 prices[0] = 1
  • 在此处卖出 prices[3] = 8
  • 在此处买入 prices[4] = 4
  • 在此处卖出 prices[5] = 9
  • 总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

注意:

  • 0 < prices.length <= 50000.
  • 0 < prices[i] < 50000.
  • 0 <= fee < 50000.

思路:

本题和前面两题比起来简直就是小儿科,这道题更像是“122.买卖股票的最佳时机II”的进阶版本,唯一区别就是卖股票要多一个减去手续费的操作。所以只单独讲解递推公式部分

本题dp数组的含义是:dp[i][0] 表示第i天持有股票所得最多现金。 dp[i][1] 表示第i天不持有股票所得最多现金。

那么如果第i天我们持有股票,可以从两种状态推出来,要么i -1 天就持有股票了,今天维持现状而已。要么i-1 天没持有股票,今天把股票买进来了,那现在的现金就得扣掉今天的股票价格,所以:dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);

而如果第i天没持有股票,同样两种可能,可以是昨天就没持有,今天保持不变。也可以是昨天持有股票,今天卖掉了,那么现在手里的现金就能加上今天股票的卖价,但是注意还得扣掉手续费(此处是与“122.买卖股票的最佳时机II”唯一有差别的点),即dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);

其他代码完全一致

代码示例:

function maxProfit(prices: number[], fee: number): number { const length: number = prices.length if (length === 0) return 0 const dp: number[][] = new Array(length).fill(0).map(_ => []) dp[0][0] = -prices[0] dp[0][1] = 0 for (let i = 1; i < 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[length - 1][1] };
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 12:10:12

医疗PINN漏生物力学约束 手术导航轨迹全偏 补物理方程才校准

&#x1f4dd; 博客主页&#xff1a;jaxzheng的CSDN主页 目录我和医疗数据科学的相爱相杀史&#xff1a;当Excel遇上CT片 一、从Excel到CT片&#xff1a;一个普通社畜的觉醒 二、当AI开始读CT&#xff1a;从"人机大战"到"人机协作" 三、数据隐私的那些事儿…

作者头像 李华
网站建设 2026/4/23 15:00:11

DownKyi视频下载工具:专业级B站内容管理解决方案

DownKyi视频下载工具&#xff1a;专业级B站内容管理解决方案 【免费下载链接】downkyi 哔哩下载姬downkyi&#xff0c;哔哩哔哩网站视频下载工具&#xff0c;支持批量下载&#xff0c;支持8K、HDR、杜比视界&#xff0c;提供工具箱&#xff08;音视频提取、去水印等&#xff09…

作者头像 李华
网站建设 2026/4/22 14:41:27

华为设备--链路聚合全套配置

华为设备--链路聚合全套配置华为设备链路聚合配置指南基本概念配置步骤&#xff08;手工模式&#xff09;配置步骤&#xff08;LACP动态模式&#xff09;高级配置选项故障排查命令华为设备链路聚合配置指南 链路聚合&#xff08;Link Aggregation&#xff09;通过将多个物理接…

作者头像 李华
网站建设 2026/4/23 12:09:19

飞书文档批量导出终极指南:一键备份700+文档的完整解决方案

飞书文档批量导出终极指南&#xff1a;一键备份700文档的完整解决方案 【免费下载链接】feishu-doc-export 项目地址: https://gitcode.com/gh_mirrors/fe/feishu-doc-export 在数字化办公时代&#xff0c;飞书文档已成为企业和个人日常工作的核心工具。feishu-doc-exp…

作者头像 李华
网站建设 2026/4/23 13:30:25

微信网页版访问终极攻略:告别“无法访问“的烦恼

微信网页版访问终极攻略&#xff1a;告别"无法访问"的烦恼 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 还在为微信网页版频繁出现的&quo…

作者头像 李华
网站建设 2026/4/23 12:10:33

网络安全校招:3 类入门岗位薪资 + 技能要求,清晰对标

网络安全校招&#xff1a;3 类入门岗位薪资 技能要求&#xff0c;清晰对标 2025 年网络安全人才缺口已突破 150 万&#xff0c;北京、深圳等城市企业甚至开出 “应届生年薪 30 万 ” 的高薪抢人。但对高校应届生而言&#xff0c;“岗位类型繁杂、技能要求模糊” 往往成为求职路…

作者头像 李华