首页/新闻资讯/正文详情

C++实现LeetCode(309.买股票的最佳时间含冷冻期)

发布时间:2026/11/6 6:55:21 来源:云帆数科 栏目:资讯中心
C++实现LeetCode(309.买股票的最佳时间含冷冻期)
前言LeetCode 309 是股票买卖系列里状态最多的一题允许多次买卖但卖出股票的第二天不能买入也就是有一天的冷冻期。求能获得的最大利润。题目通常给出一个整数数组pricesprices[i]表示第i天的股价。这题的难点不在代码长度而在状态定义持有股票、当天卖出、冷冻期、正常不持有这几种状态之间的转移容易混淆。常见的错误包括把“卖出后第二天不能买”写成“卖出当天不能买”用sold[0] 0初始化凭空得到一笔卖出收益把买入的来源写成前一天卖出导致冷冻期被跳过最后返回持有股票的状态以及滚动变量更新时用已覆盖的旧值计算新值。本文以 C17 为准用三个状态建立动态规划hold持有股票、sold当天刚卖出、rest不持有且不在冷冻期。先写二维版本说明转移再压缩成常数空间。所有推导都是按状态定义手工进行的不涉及运行结果。一、状态定义把第i天结束时的状态分为三类状态含义当天结束时的现金hold手里持有股票买入花费后的现金可能为负sold当天卖出了股票卖出后的现金rest不持有股票且不处于“刚卖出”的冷冻期现金这里的“现金”只计算交易带来的盈亏初始为 0。买入时减去股价卖出时加上股价。为什么需要sold和rest两个“不持有”状态因为冷冻期的限制只作用于“刚卖出的下一天”。如果把所有不持有状态合并成一个就无法区分“昨天刚卖今天不能买”和“已经空仓一段时间今天可以买”。状态转移持有要么昨天就持有今天不动要么今天买入。今天能买入的前提是昨天处于rest不持有且不在冷冻期。所以hold[i] max(hold[i-1], rest[i-1] - prices[i])。当天卖出昨天必须持有今天按prices[i]卖出sold[i] hold[i-1] prices[i]。空仓休息要么昨天就已经在休息要么昨天刚卖出今天进入冷冻期rest[i] max(rest[i-1], sold[i-1])。注意hold的买入来源是rest[i-1]不是sold[i-1]。如果第i-1天卖出第i天是冷冻期不能买入而rest[i]的转移允许sold[i-1]进入休息状态到第i1天才能从rest[i]买入。这正是“卖后隔一天才能买”的体现。二、初始化与答案第 0 天买入hold[0] -prices[0]卖出第 0 天不可能卖出没有前一天持仓应设为负无穷休息rest[0] 0表示什么都没做。sold[0]不能设为 0。设为 0 相当于“第 0 天无成本卖出得到 0 元”后续可能被错误地当成有效收益甚至让答案虚高。用INT_MIN或足够小的负数表示不可达。最终答案是max(sold[n-1], rest[n-1])不能是hold[n-1]。最后一天还持有股票说明没有卖出收益尚未兑现题目要求的是完成交易后的最大利润。sold和rest都表示不持有取两者较大值即可。若prices为空利润为 0若只有一个元素无法完成一次买卖利润也是 0。这两种情况要在代码入口处理。三、二维 DP 写法先写出完整表格版本便于核对状态// 适用于 C17#include algorithm#include limits#include vectorint max_profit_2d(const std::vectorint prices){const int n static_castint(prices.size());if (n 2)return 0;const long long NEG std::numeric_limitslong long::min() / 2;std::vectorlong long hold(n, NEG);std::vectorlong long sold(n, NEG);std::vectorlong long rest(n, 0);hold[0] -prices[0];for (int i 1; i n; i){hold[i] std::max(hold[i - 1], rest[i - 1] - prices[i]);sold[i] hold[i - 1] prices[i];rest[i] std::max(rest[i - 1], sold[i - 1]);}return static_castint(std::max(sold[n - 1], rest[n - 1]));}NEG取long long最小值的一半是为了在sold[i] hold[i-1] prices[i]中避免溢出。实际上hold[i-1]从第 1 天起就已是有效值要么是-prices[0]要么是买入后的现金不会用到NEG但保留这个保护不影响正确性。用题目常见的例子prices [1, 2, 3, 0, 2]手工推演天数 i价格holdsoldrest01-1不可达012-11023-121301-1242132第 4 天结束时sold 3、rest 2答案是 3。交易过程可以是第 0 天买、第 2 天卖赚 2冷冻第 3 天第 3 天买、第 4 天卖赚 2总利润 4这里要小心第 2 天卖出后第 3 天是冷冻期不能买入。因此上面的 3 对应的交易是第 0 天买、第 1 天卖赚 1第 2 天买、第 4 天卖第 2 天卖出后第 3 天冷冻不能第 2 天买。让我按状态回溯第 4 天sold hold[3] 2 1 2 3hold[3] 1来自rest[2] - 0 1 - 0 1即第 2 天休息后第 3 天以 0 买入rest[2] 1来自sold[1] 1即第 1 天卖出。第 1 天的卖出来自第 0 天买入-1 2 1。所以交易是第 0 天买、第 1 天卖1第 2 天冷冻第 3 天买、第 4 天卖2总计 3。正确。第 2 天卖出再第 3 天买是违反冷冻期的手工推演时正好能暴露这种错误理解。这个例子说明冷冻期是“卖出后的下一个交易日”不是“卖出当天”。第 1 天卖出第 2 天不能买第 2 天休息第 3 天才能买。四、滚动变量常数空间二维表只依赖前一天因此可以用三个变量滚动// 适用于 C17#include algorithm#include limits#include vectorint max_profit(const std::vectorint prices){if (prices.size() 2)return 0;const long long NEG std::numeric_limitslong long::min() / 2;long long hold -prices[0];long long sold NEG;long long rest 0;for (std::size_t i 1; i prices.size(); i){const long long price prices[i];const long long next_hold std::max(hold, rest - price);const long long next_sold hold price;const long long next_rest std::max(rest, sold);hold next_hold;sold next_sold;rest next_rest;}return static_castint(std::max(sold, rest));}三个next_临时变量必须全部算完再统一赋值。如果写成hold std::max(hold, rest - price);sold hold price; // 错误hold 已被更新rest std::max(rest, sold); // 错误sold 已被更新那么sold会用到“今天已经买入后的 hold”相当于同一天既买又卖rest也会用到今天的sold冷冻期被压缩。这类错误在滚动数组里很常见根源是没有区分“前一天的状态”和“今天的状态”。时间复杂度和空间复杂度都是O(n)时间和O(1)额外空间不计输入。五、另一种等价写法也可以用两个数组hold和cash其中cash[i]表示第i天结束时不持有股票的现金买入时要求从前两天的不持有状态转移// 适用于 C17int max_profit_alt(const std::vectorint prices){const int n static_castint(prices.size());if (n 2)return 0;std::vectorint hold(n, 0);std::vectorint cash(n, 0);hold[0] -prices[0];cash[0] 0;for (int i 1; i n; i){hold[i] std::max(hold[i - 1], (i 2 ? cash[i - 2] : 0) - prices[i]);cash[i] std::max(cash[i - 1], hold[i - 1] prices[i]);}return cash[n - 1];}这里cash[i-2]的含义是如果第i-1天卖出第i天处于冷冻期不能用cash[i-1]买入只能用第i-2天结束时的现金。i 2时第 0 天或第 1 天买入都不受冷冻期限制用初始现金 0。两种写法等价但三状态版本把“冷冻期”显式建模转移条件的含义更直观两状态版本更短但i 2的下标容易写错。面试或刷题时选一种自己能手推清楚的即可不要在两种记法之间来回切换。六、边界与变体需要检查的边界prices为空返回 0不能访问prices[0]只有一个价格无法完成买卖返回 0价格全部下跌最优是不交易答案为 0价格全部相同不交易答案为 0冷冻期跨过数组末尾最后一天卖出后没有后续买入答案仍按sold计算不需要额外处理。股票系列题容易混淆变体题目约束状态差异121只能买卖一次维护最小价格或单次持有状态122可多次买卖无冷冻期持有/不持有两状态卖出后可立即买309可多次买卖卖后冷冻一天需要区分“刚卖出”和“休息”714可多次买卖有手续费卖出时减去手续费188最多 k 次交易增加交易次数维度把 309 的rest状态去掉、允许sold[i-1]直接买入就退化成 122在卖出时减去fee就得到 714 的无冷冻期版本。理解状态机后这些变体只是在转移式上增减项。常见坑点❌ 把sold[0]初始化为 0。✅ 第 0 天不可能卖出应设为负无穷否则会凭空产生收益污染后续转移。❌ 买入来源写成sold[i-1] - prices[i]。✅ 卖出后第二天不能买买入只能来自rest[i-1]sold[i-1]要到rest[i]才可用。❌ 把冷冻期理解为“卖出当天不能买”。✅ 卖出当天本来就不能同时买限制的是卖出后的下一个交易日即第i天卖出第i1天不能买。❌ 最终返回hold[n-1]。✅ 返回max(sold[n-1], rest[n-1])持有股票意味着尚未卖出利润没有兑现。❌ 滚动更新时先改hold再算sold用了今天的状态。✅ 先把next_hold、next_sold、next_rest都算出来再统一赋值。❌ 用int存负无穷并直接加价格导致溢出。✅ 用足够小的负数如INT_MIN / 2或long long避免加法溢出。❌ 忘记处理空数组或单元素数组访问prices[0]越界。✅ 入口处判断prices.size() 2直接返回 0。❌ 把 309 的转移直接套到 122无冷冻期答案偏小。✅ 先确认题目约束无冷冻期时卖出后可以立即买入不需要rest的延迟。总结项目内容状态hold持有、sold当天卖出、rest空仓休息持有转移max(hold, rest - price)卖出转移hold price休息转移max(rest, sold)初始值hold -prices[0]sold 负无穷rest 0答案max(sold, rest)时间/空间O(n)/O(1)309 的关键是把“冷冻期”建模成一个独立状态而不是在买入时临时判断。sold表示“今天刚卖明天不能买”rest表示“已经空仓随时可买”两者分开后转移式自然满足“卖后隔一天”的约束。写完后用[1,2,3,0,2]这类包含下跌和反弹的例子手工推演一遍重点检查买入来源和滚动变量的更新顺序基本就能排除大多数错误。

相关推荐

pgvector:PostgreSQL向量搜索扩展原理与实践
pgvector:PostgreSQL向量搜索扩展原理与实践

1. pgvector 核心原理与架构设计1.1 什么是 pgvector?pgvector 是 PostgreSQL 的开源扩展(Extension),为世界上最先进的开源关系型数据库添加向量相似度搜索能力。与 Pinecone(SaaS)和 Milvus(独… · 2026/11/6 6:55:21

消息队列核心原理与应用实践:从异步处理到系统解耦
消息队列核心原理与应用实践:从异步处理到系统解耦

1. 消息队列的核心价值与应用场景第一次接触消息队列是在2016年处理电商秒杀系统时。当时我们的服务器在流量高峰时频繁崩溃,直到引入RabbitMQ后才真正理解了异步处理的价值。消息队列(Message Queue)本质上是一种应用程序间的通信方式&#… · 2026/11/6 6:55:21

Shopify后台操作指南与高效运营技巧
Shopify后台操作指南与高效运营技巧

1. Shopify 后台界面概览当你第一次登录Shopify后台(yourstore.myshopify.com/admin),可能会被各种菜单选项搞得眼花缭乱。作为一位运营过数十家Shopify店铺的老手,我可以告诉你,理解这个界面布局是高效管理店铺的第一… · 2026/11/6 6:55:21

微信小程序+物联网打造无人羽毛球馆系统
微信小程序+物联网打造无人羽毛球馆系统

1. 项目概述 作为一名长期从事体育场馆数字化改造的技术人员,最近完成了一个基于微信小程序的无人羽毛球馆系统开发项目。这个系统彻底改变了传统羽毛球馆的运营模式,实现了从场地预约到入场使用的全流程自助化服务。 传统羽毛球馆普遍存在几个痛点&… · 2026/11/6 11:51:35

2025服装电商ERP系统选型与技术架构解析
2025服装电商ERP系统选型与技术架构解析

1. 服装电商ERP行业现状与核心痛点 服装行业作为电商领域最活跃的垂直赛道之一,其ERP系统选型直接影响着企业从生产到销售的全链路效率。2025年的市场数据显示,头部服装电商企业平均每天需要处理超过3000个SKU的进销存管理,这对ERP系统的实时… · 2026/11/6 11:51:35

AI快捷键进阶:五组组合键打通设计操作链
AI快捷键进阶:五组组合键打通设计操作链

大多数人电脑里都存着一张AI(Adobe Illustrator)快捷键大全的截图,两三百个键位,看了几眼就再也没打开过。真正动手的时候,手还是慢:画一个等距排列的图标,一个个复制粘贴再对齐,二十… · 2026/11/6 11:51:35

通信信号接收技术:从匹配滤波器到分集接收
通信信号接收技术:从匹配滤波器到分集接收

1. 通信信号接收的本质挑战 在通信系统设计中,信号接收质量直接决定了信息传输的可靠性。根据信号特性的不同,我们可以将待接收信号分为三类:确定信号、随相信号和起伏信号。这三种信号类型代表了从理想环境到复杂现实场景的过渡,… · 2026/11/6 11:50:33

Python数据分析与可视化:从工具选型到实战避坑的完整指南
Python数据分析与可视化:从工具选型到实战避坑的完整指南

简介:这份PDF面向希望入门或巩固Python数据分析与可视化技能的读者,尤其适合零基础学习者、在校学生及需要快速上手数据处理的职场人士。内容围绕Pandas、NumPy、SciPy、StatModels等数据分析库与Matplotlib、Seaborn、Plotly、Bokeh、Cufflinks等可视化… · 2026/11/6 11:49:33

Redis主从同步机制解析与优化实践
Redis主从同步机制解析与优化实践

1. Redis主从同步的本质与挑战Redis主从同步远非简单的数据拷贝过程,而是一个精心设计的分布式系统状态同步机制。在实际生产环境中,我们常常会遇到这样的场景:一个承载着每秒数万次读写请求的Redis主节点,如何在保持服务不中断的… · 2026/11/6 11:49:33

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23

三菱PLC数据采集到数据库的时序设计:Python+MC协议实战
三菱PLC数据采集到数据库的时序设计:Python+MC协议实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

ASIC主模式RTL设计:状态机与三态驱动的流片级实现
ASIC主模式RTL设计:状态机与三态驱动的流片级实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

STM32嵌入式C++开发:GDB调试与Renode仿真实战指南
STM32嵌入式C++开发:GDB调试与Renode仿真实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 1:02:11

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/6 10:29:23

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码