当前位置: 首页 > news >正文

买卖股票的最佳时机(动态规划方法总结)

总结一下,买卖股票系列的动态规划思想,贪心解法或者其他解法不做描述。

总结

121. 买卖股票的最佳时机 只有一次交易机会,每天有两种状态:持有股票和不持有股票;

122. 买卖股票的最佳时机 II 有多次交易机会,每天有两种状态:持有股票和不持有股票;

123. 买卖股票的最佳时机 III 至多两次交易机会,每天有 2*2=4 种状态:第一次持有股票;第一次不持有股票;第二次持有股票;第二次不持有股票;

188. 买卖股票的最佳时机 IV - 力扣(LeetCode)至多 k 次交易机会,与买卖股票 3 相比,每天有 2*k=2k 种状态:第一次持有股票;第一次不持有股票;第二次持有股票;第二次不持有股票... 第 k 次持有股票;第 k 次不持有股票。

买卖股票的最佳时机 Ⅰ

题目描述:给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

买卖股票系列的第一题,核心是只有一次交易机会

dp 数组建立:

用两个 dp 数组来描述:

  • dp[i][0] 第 i 天持有股票的最大剩余现金
  • dp[i][1] 第 i 天不持有股票的最大剩余现金

重要的是理解这里的“剩余现金”是什么含义:一开始,我们持有的现金为 0,买入一支股票i后,我们持有股票的剩余现金就是-prices[i],而在第 i+k 天卖出股票后,我们不持有股票的剩余现金就是 prices[i+k] - prices[i],也就是交易后的利润。

dp[0][0] = -prices[0]; 因为第 0 天要持有股票,只能购入第一支股票,剩余现金为 -prices[0]

dp[0][1] = 0; 因为第 0 天只能买入股票,无法卖出股票,因此 dp[0][1] 初始化为 0。


递推公式:

  • dp[i][0] = max(dp[i-1][0], -prices[i]);第 i 天持有股票,有两种情况:
    • 第一种,第 i不买入股票,那么第 i天持有股票的剩余现金就是第 i-1天持有股票的剩余现金,即dp[i][0] = dp[i-1][0];
    • 第二种,第 i买入股票,那么第 i天持有股票的剩余现金就是 0 减去第 i 天的股票价格,即dp[i][0] = -prices[i];
    • 两者取最大值。
  • dp[i][1] = max(dp[i-1][1], prices[i] + dp[i-1][0]);同样有两种情况:
    • 第一种,i 天前已经不持有股票,那么第 i天持有股票的剩余现金就是第 i-1天持有股票的剩余现金,即dp[i][1] = dp[i-1][1];
    • 第二种,i 天当天才不持有股票,那么第 i天持有股票的剩余现金就是第 i 天的股票价格 + 第 i-1 天持有股票的最大剩余现金,即dp[i][1] = prices[i] + dp[i-1][0];
    • 两者取最大值。

完整代码:

class Solution {
public:int maxProfit(vector<int>& prices) {int n = prices.size();// dp[i][0] 第 i 天持有股票的最大剩余现金;// dp[i][1] 第 i 天不持有股票的最大剩余现金。vector<vector<int>> dp(n, vector<int>(2, 0));dp[0][0] = -prices[0];dp[0][1] = 0;for (int i = 1; i < n; ++i) {dp[i][0] = max(dp[i - 1][0], -prices[i]);dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);}return dp[n - 1][1];}
};

买卖股票的最佳时机 Ⅱ

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润

买卖股票系列的第二题,和第一题的不同之处在于,可以多次买卖股票

dp 数组建立:

用两个 dp 数组来描述:

  • dp[i][0] 第 i 天持有股票的最大剩余现金
  • dp[i][1] 第 i 天不持有股票的最大剩余现金

dp[0][0] = -prices[0]; 因为第 0 天要持有股票,只能购入第一支股票,剩余现金为 -prices[0]

dp[0][1] = 0; 因为第 0 天不管是不买股票,还是买了再卖出股票,都无法获得利润,因此 dp[0][1] 初始化为 0。


递推公式:

  • dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]);第 i 天持有股票,有两种情况:
    • 第一种,第 i不买入股票,那么第 i天持有股票的剩余现金就是第 i-1天持有股票的剩余现金,即dp[i][0] = dp[i-1][0];
    • 第二种,第 i买入股票,那么第 i-1 天就不能持有股票,因为在这道题目中连续购买两支股票没有意义,只会多花钱。第 i天持有股票的剩余现金就是 第 i-1 天不持有股票的最大剩余现金减去第 i 天的股票价格,即dp[i][0] = dp[i-1][1] - prices[i];
    • 两者取最大值。
  • dp[i][1] = max(dp[i-1][1], prices[i] + dp[i-1][0]);同样有两种情况:
    • 第一种,i 天前已经不持有股票,那么第 i天持有股票的剩余现金就是第 i-1天持有股票的剩余现金,即dp[i][1] = dp[i-1][1];
    • 第二种,i 天当天才不持有股票,同理,第 i-1 天必须是持有股票的,没有持有股票,怎么卖出股票呢?第 i天持有股票的剩余现金就是第 i 天的股票价格 + 第 i-1 天持有股票的最大剩余现金,即dp[i][1] = prices[i] + dp[i-1][0];
    • 两者取最大值。

完整代码:

class Solution {
public:int maxProfit(vector<int>& prices) {// 动态规划// dp[i][0] 表示第i天持有股票的最少消耗// dp[i][1] 表示第i天持有股票的最大利润vector<vector<int>> dp(prices.size(), vector<int>(2, 0));dp[0][0] = -prices[0];dp[0][1] = 0;for (int i = 1; i < prices.size(); ++i) {dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);}return dp[prices.size() - 1][1];}
};

总结:

本题和121. 买卖股票的最佳时机的代码几乎一样,唯一的区别在:

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

因为本题的股票可以买卖多次! 所以买入股票的时候,剩余现金可能包含之前买卖的所得利润:dp[i - 1][1],所以 dp[i][0] 可能会等于 dp[i-1][1] - prices[i]

想到到这一点,对这两道题理解的就比较深刻了。

买卖股票的最佳时机 Ⅲ

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

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

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

这题,要求我们在购入股票时,手上不能持有其他股票,且最多只能进行两笔交易

前两道题,同一天只有两种状态:持有股票或者不持有股票

对于这道题,同一天可以有 4 种状态:

  1. 第一次持有股票
  2. 第一次不持有股票
  3. 第二次持有股票
  4. 第二次不持有股票

那么 dp[i][j] 就表示第 i 天的 j 状态下的最大剩余现金。

dp[0][0] = -prices[0];第 0 天第一次买入;

dp[0][1] = 0;

dp[0][2] = -prices[0];第 0 天第二次买入(第一次买入后卖出,再买入,有点蛇精病,但是为了做题,只能这么买了)

dp[0][3] = 0;


递推公式:

  1. 第 i 天第一次持有股票的最大剩余金额 = max(第 i-1 天第一次持有股票的最大剩余金额, -第 i 天股票价格)
  2. 第 i 天第一次不持有股票的最大剩余金额 = max(第 i-1 天第一次不持有股票的最大剩余金额, 第 i 天股票价格 + 第 i-1 天第一次持有股票的最大剩余金额)
  3. 第 i 天第二次持有股票的最大剩余金额 = max(第 i-1 天第二次持有股票的最大剩余金额, 第 i-1 天第一次不持有股票的最大剩余金额 - 第 i 天股票价格)
  4. 第 i 天第二次不持有股票的最大剩余金额 = max(第 i-1 天第二次不持有股票的最大剩余金额, 第 i-1 天第二次持有股票的最大剩余金额 + 第 i 天股票价格)
dp[i][0] = max(dp[i - 1][0], -prices[i]);
dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] - prices[i]);
dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] + prices[i]);;

完整代码:

注意,两次卖出的状态剩余现金最大一定是最后一次卖出。可以这么理解:如果第一次卖出已经是最大值了,那么我们可以在当天立刻买入再立刻卖出。所以dp[4][4]已经包含了dp[4][2]的情况。也就是说第二次卖出的剩余现金一定是最多的。

class Solution {
public:int maxProfit(vector<int>& prices) {// 动态规划// 1. 第一次持有股票// 2. 第一次不持有股票// 3. 第二次持有股票// 4. 第二次不持有股票vector<vector<int>> dp(prices.size(), vector<int>(4, 0));dp[0][0] = -prices[0];dp[0][1] = 0;dp[0][2] = -prices[0];dp[0][3] = 0;for (int i = 1; i < prices.size(); ++i) {dp[i][0] = max(dp[i - 1][0], -prices[i]);dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);dp[i][2] = max(dp[i - 1][2], dp[i - 1][1] - prices[i]);dp[i][3] = max(dp[i - 1][3], dp[i - 1][2] + prices[i]);;}int result = max( dp[prices.size() - 1][1], dp[prices.size() - 1][3] );return result;}
};

买卖股票的最佳时机 Ⅳ

给你一个整数数组 prices 和一个整数 k ,其中 prices[i] 是某支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多可以买 k 次,卖 k 次。

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

与 123. 买卖股票的最佳时机 III 不同,这一次,我们最多可以完成 k 笔交易

那如果按照 3 的思路,我们可以用 dp[i][2 * k] 来描述第 i 天的 2k 种不同状态。

完整代码:

class Solution {
public:int maxProfit(int k, vector<int>& prices) {// 动态规划// 1. 第一次持有股票 dp[i][0]// 2. 第一次不持有股票 dp[i][1]// 3. 第二次持有股票 dp[i][2]// 4. 第二次不持有股票 dp[i][3]// ...//      k次持有 dp[i][2 * k - 2]//      k次不持有 dp[i][2 * k - 1]vector<vector<int>> dp(prices.size(), vector<int>(2 * k, 0));for (int i = 0; i < 2 * k; i+=2) {dp[0][i] = -prices[0];}for (int i = 1; i < prices.size(); ++i) {// 计算第一次的两个状态dp[i][0] = max(dp[i - 1][0], -prices[i]);dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);for (int j = 2; j <= k; ++j) {// 计算第2次到第k次的所有状态dp[i][2 * j - 2] = max(dp[i - 1][2 * j - 2], dp[i - 1][2 * j - 3] - prices[i]);dp[i][2 * j - 1] = max(dp[i - 1][2 * j - 1], dp[i - 1][2 * j - 2] + prices[i]);}}int result = dp[prices.size() - 1][2 * k - 1];return result;}
};

相关文章:

买卖股票的最佳时机(动态规划方法总结)

总结一下&#xff0c;买卖股票系列的动态规划思想&#xff0c;贪心解法或者其他解法不做描述。 总结 121. 买卖股票的最佳时机 只有一次交易机会&#xff0c;每天有两种状态&#xff1a;持有股票和不持有股票&#xff1b; 122. 买卖股票的最佳时机 II 有多次交易机会&#x…...

KubeSphere安装mysql8.4.0

背景 KubeSphere 是在 Kubernetes 之上构建的以应用为中心的多租户容器平台,完全开源,提供全栈的 IT 自动化运维的能力,简化企业的 DevOps 工作流。KubeSphere 提供了运维友好的向导式操作界面&#xff0c;帮助企业快速构建一个强大和功能丰富的容器云平台。 安装组件前提&am…...

SpringBoot项目热部署-devtools

DevTools 会使用两个类加载器&#xff08;一个用于加载不变的类&#xff0c;一个用于加载可能会变化的类&#xff09;&#xff0c;每次重启只重新加载管理变化的类的加载器&#xff0c;因此会快很多 1.导入依赖 <dependency> <groupId>org.springframework.boot&l…...

从MySQL到OceanBase离线数据迁移的实践

本文作者&#xff1a;玉璁&#xff0c;OceanBase 生态产品技术专家。工作十余年&#xff0c;一直在基础架构与中间件领域从事研发工作。现负责OceanBase离线导数产品工具的研发工作&#xff0c;致力于为 OceanBase 建设一套完善的生态工具体系。 背景介绍 在互联网与云数据库技…...

ifconfig 和 ip addr

1. 工具所属套件 ifconfig&#xff1a;属于较老的 net-tools 套件。曾是 Unix 和 Linux 系统上广泛使用的工具。ip addr&#xff1a;属于较新的 iproute2 套件。它取代了 ifconfig&#xff0c;并逐渐成为现代 Linux 系统上更常用的工具。 2. 功能覆盖范围 ifconfig&#xff…...

NCCL报错

1、报错信息&#xff1a; raise RuntimeError("Distributed package doesnt have NCCL " "built in") RuntimeError: Distributed package doesnt have NCCL built in 2、报错原因&#xff1a; windows系统不支持nccl&#xff0c;采用gloo&#xff1b; …...

域7:安全运营 第16章 安全运营管理

第七域包括 16、17、18、19 章。 第七域所涵盖的广泛知识点&#xff0c;与我们的安全运营工作之间存在着高度的契合性。这些知识点不仅为我们的安全运营提供了有力的理论支撑&#xff0c;还使得SOC&#xff08;安全运营中心&#xff09;在日常运作中能够更加高效地发挥作用。通…...

研发线上事故风险解读之数据库存储

专业在线打字练习平台-巧手打字通&#xff0c;只输出有价值的知识。 一 前言 本文继续基于《线上事故案例集》&#xff0c;进一步深入梳理线上事故数据存储方面的问题点&#xff0c;重点关注数据库存储在使用和优化过程中可能出现的问题&#xff0c;旨在为读者提供具有实践指导…...

react hooks中在setState后输出state为啥没有变化,如何解决

在 React Hooks 中&#xff0c;setState 的概念被 useState 或 useReducer 钩子所替代。与类组件中的 setState 一样&#xff0c;这些钩子也是异步更新状态的。因此&#xff0c;如果你尝试在调用 setState&#xff08;即 setXXX 函数&#xff09;后立即读取状态值&#xff0c;你…...

C++设计模式——代理模式

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 引言代理模式的定义代理模式的具体实现 引言 我们经常听到代理服务器「代理服务器是一个中间服务器&#xff0c;能够接收客户端的请求&#xff0c;并代表客户端向服务器发起请求&#xff0c;然后将服…...

docker 复制文件,清除不再使用数据导出以及导出文件系统

docker cp -a centos :/etc/centos-release #将容器内文件复制到宿主机 docker cp /etc/issue centos:/root #将宿主机文件复制到容器内 docker export&#xff1a; 将一个运行的或者挺值得容器的文件系统导出为一个tar归档文件。需要注意&#xff0c;docker export 不会包含该…...

【Vue】Vue3.0(十一)Vue 3.0 中 computed 计算属性概念、使用及示例

上篇文章&#xff1a;【Vue】Vue3.0&#xff08;十&#xff09;toRefs()和toRef()的区别及使用示例 &#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Vue专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年10月15日10点23分 文章目录 Vue 3.0中…...

【第三版 系统集成项目管理工程师】第17章 法律法规和标准规范

持续更新。。。。。。。。。。。。。。。 【第三版】第17章 法律法规和标准规范 17.1法律法规17.1.1 法与法律 P5801.基本概念-P5802.本质与特征-P580 17.1.2 法律体系1.世界法律体系(非重点)-P5802.中国特色社会主义法律体系-P581 17.1.3 法的效力1.对象效力-P5822.空间效力-…...

安装 LLM 编程工具 cursor

1&#xff0c;网址 cursor.com 点击 Download for Free 下载安装包 下载到一个300KB的安装压缩包&#xff0c;解压后双击后&#xff0c;点 open 安装过成会下载真正的应用程序 点击 continue 登陆 比如选择使用 github账号登陆 则会弹出如下网页&#xff1a; 先登陆 github&a…...

Java链式编程的定义、例子、使用方法、实际应用场景、自动装配构造

链式编程&#xff08;Fluent Interface&#xff09;是一种编程风格&#xff0c;允许通过方法调用连接在一起进行操作&#xff0c;通常用于提高代码的可读性和简洁性。在 Java 中&#xff0c;链式编程常通过返回 this&#xff08;当前对象&#xff09;来实现。这种做法在构建器模…...

用 Git Stash 临时保存修改,轻松切换任务!

在开发过程中&#xff0c;我们经常会遇到这样的情况&#xff1a;正在写代码&#xff0c;突然领导或同事让你赶紧处理一个紧急 bug&#xff0c;但你当前的代码还没写完&#xff0c;不能提交&#xff0c;这时候该怎么办呢&#xff1f;别慌&#xff0c;Git 的 stash 命令正好能帮上…...

Android 下通过触发 SIGTRAP 信号实现反调试

版权归作者所有&#xff0c;如有转发&#xff0c;请注明文章出处&#xff1a;https://cyrus-studio.github.io/blog/ 详细的 Linux 信号列表 Linux 信号是一种用于进程间通信&#xff08;IPC&#xff09;和异常处理的机制。以下是详细的 Linux 信号列表&#xff0c;包含信号名…...

【MySQL】 表的增删操作

目录 1.Create&#xff08;增&#xff09; 1.1.单行数据 全列插入 1.2.多行数据 指定列插入 1.3.插入否则更新 1.4.替换数据&#xff08;REPLACE&#xff09; 2.Delete&#xff08;删&#xff09; 2.1.删除表中的某个条目 2.2.删除整张表数据 2.3.截断表 1.Create…...

新生入门季 | 学习生物信息分析,如何解决个人电脑算力不足的问题?

随着生物信息学在科研和教育中的快速普及&#xff0c;越来越多的新生开始接触基因组测序、RNA分析等复杂计算任务。然而&#xff0c;在面对这些大规模数据时&#xff0c;个人电脑的算力往往显得捉襟见肘。你是否也在为自己的笔记本性能不足而苦恼&#xff1f; 这篇文章将为你提…...

20255 - 中医方剂学 - 考研 - 执业

第1章 总论 1.我国现存最早的记载方剂的医书是&#xff08;&#xff09;( ) [单选] A.《太平圣惠方》 B.《黄帝内经》 C.《五十二病方》 D.《千金要方》 E.《外台秘要》 正确答案: C 2.我国最早的中医经典理论著作是&#xff08;&#xff09;( ) [单选] A.《伤寒杂病论…...

【杂谈】-递归进化:人工智能的自我改进与监管挑战

递归进化&#xff1a;人工智能的自我改进与监管挑战 文章目录 递归进化&#xff1a;人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管&#xff1f;3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)

安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...

MySQL 8.0 事务全面讲解

以下是一个结合两次回答的 MySQL 8.0 事务全面讲解&#xff0c;涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容&#xff0c;并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念&#xff08;ACID&#xff09; 事务是…...

【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统

Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...

计算机系统结构复习-名词解释2

1.定向&#xff1a;在某条指令产生计算结果之前&#xff0c;其他指令并不真正立即需要该计算结果&#xff0c;如果能够将该计算结果从其产生的地方直接送到其他指令中需要它的地方&#xff0c;那么就可以避免停顿。 2.多级存储层次&#xff1a;由若干个采用不同实现技术的存储…...

【Vue】scoped+组件通信+props校验

【scoped作用及原理】 【作用】 默认写在组件中style的样式会全局生效, 因此很容易造成多个组件之间的样式冲突问题 故而可以给组件加上scoped 属性&#xff0c; 令样式只作用于当前组件的标签 作用&#xff1a;防止不同vue组件样式污染 【原理】 给组件加上scoped 属性后…...