Day49【动态规划】121.买卖股票的最佳时机、122.买卖股票的最佳时机II

news2025/1/12 18:10:21

121.买卖股票的最佳时机

力扣题目链接/文章讲解

视频讲解 

动态规划五部曲!

1、确定 dp 数组下标及值的含义 

先想想本题 dp 应该怎么定义,别忘了之前说的,dp 数组的下标能够表示状态

在股票问题中,某个状态需要描述在某天,及是否持有股票

因此我们定义 dp 数组下标及值含义:

dp[i][0]:下标表示在第 i 天,未持有股票,值表示第 i 天未持有股票所得最多现金

dp[i][1]:下标表示在第 i 天,持有股票,值表示第 i 天持有股票所得最多现金

通过第一个下标 i 描述在哪一天,第二个下标为 0 或 1 描述在该天未持有或持有股票,这样通过两个下标就能够描述所有的状态了

2、确定递推公式

分别思考 dp[i][0] 和 dp[i][1] 分别应该怎么推

dp[i][0]:需要求第 i 天未持有股票所得最多现金,要考虑怎么转移到第 i 天未持有股票的这种状态

  • 可能是在第 i 天卖出了股票,所得现金就是昨天持有股票,然后今天卖出股票后所得现金,即:dp[i - 1][1](昨天持有股票)+ prices[i](今天卖出股票)
  • 可能是在第 i - 1 天就未持有股票,那么就保持现状,所得现金就是昨天未持有股票的所得现金,即:dp[i - 1][0](昨天未持有股票)

因为求的最多现金,即 dp[i][0] = max(dp[i - 1][1] + prices[i], dp[i - 1][0]) 

同理,dp[i][1]:

  • 可能是在第 i 天买入股票,所得现金为 -prices[i](注意本题要求股票全程只能买一次,所以如果买入股票,买之前的现金一定为 0,买之后的现金一定为 -prices[i]
  • 可能是在第 i - 1 天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金,即:dp[i - 1][1](昨天持有股票)

因为求的最多现金,即 dp[i][1] = max(-prices[i], dp[i - 1][1])  

3、dp 数组初始化

从递推公式看出,求某一天 dp 需要知道其前一天的 dp 值,即都是要从dp[0][0]和dp[0][1]推导出来

那么dp[0][0]表示第 0 天未持有股票,不持有股票现金就是 0,所以 dp[0][0] = 0

dp[0][1]表示第 0 天持有股票,持有股票一定是在第 0 天买入了股票,所以 dp[0][1] = -prices[0]

4、确定遍历顺序

从递推公式可以看出 dp[i] 都是由 dp[i - 1] 推导出来的,那么一定是从前向后遍历

5、打印 dp 数组验证

代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {

        if (prices.size() == 0 || prices.size() == 1) return 0;
        
        // 定义dp数组下标及值含义
        vector<vector<int> > dp(prices.size(), vector<int>(2));
        
        // 确定递推公式:dp[i][0]和dp[i][1]分别确定

        // dp数组初始化,仅初始化第一天即可
        dp[0][0] = 0;
        dp[0][1] = -prices[0];

        // 从前往后遍历,一行一行填充
        for (int i = 1; i < prices.size(); ++i) {
            dp[i][0] = max(dp[i - 1][1] + prices[i], dp[i - 1][0]);
            dp[i][1] = max(-prices[i], dp[i - 1][1]);
        }

        // 最后一定卖了才能取得最大
        return dp[prices.size() - 1][0];
    }
};

从递推公式可以看出,dp[i] 只是依赖于 dp[i - 1] 的状态

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

可以使用滚动数组来节省空间,仅记录一天的 dp

如图所示,左边为原 dp 数组,右边是滚动数组。相当于就地更新原 dp 数组的每一行 

代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {

        if (prices.size() == 0 || prices.size() == 1) return 0;

        // 滚动数组,仅记录原二维dp的一行
        int dp[2];

        // 初始化原二维dp数组的第一行
        dp[0] = 0;
        dp[1] = -prices[0];

        // 一行一行遍历填充原二维数组
        for (int i = 1; i < prices.size(); ++i) {   // 遍历天数
            dp[0] = max(dp[1] + prices[i], dp[0]);
            dp[1] = max(-prices[i], dp[1]);
        }   // 遍历填充完毕后,滚动数组记录的是原二维dp的最后一行的数据

        return dp[0];
    }
};

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

力扣题目链接/文章讲解

视频讲解 

动态规划五部曲!

1、确定 dp 数组下标及值的含义 

先想想本题 dp 应该怎么定义,别忘了之前说的,dp 数组的下标能够表示状态

在股票问题中,某个状态需要描述在某天,及是否持有股票

因此我们定义 dp 数组下标及值含义:

dp[i][0]:下标表示在第 i 天,未持有股票,值表示第 i 天未持有股票所得最多现金

dp[i][1]:下标表示在第 i 天,持有股票,值表示第 i 天持有股票所得最多现金

通过第一个下标 i 描述在哪一天,第二个下标为 0 或 1 描述在该天未持有或持有股票,这样通过两个下标就能够描述所有的状态了

2、确定递推公式

分别思考 dp[i][0] 和 dp[i][1] 分别应该怎么推

dp[i][0]:需要求第 i 天未持有股票所得最多现金,要考虑怎么转移到第 i 天未持有股票的这种状态

  • 可能是在第 i 天卖出了股票,所得现金就是昨天持有股票,然后今天卖出股票后所得现金,即:dp[i - 1][1](昨天持有股票)+ prices[i](今天卖出股票)
  • 可能是在第 i - 1 天就未持有股票,那么就保持现状,所得现金就是昨天未持有股票的所得现金,即:dp[i - 1][0](昨天未持有股票)

因为求的最多现金,即 dp[i][0] = max(dp[i - 1][1] + prices[i], dp[i - 1][0]) 

同理,dp[i][1]:

  • 可能是在第 i 天买入股票,所得现金为 dp[i - 1][0](昨天未持有股票)- prices[i](今天买入股票)(因为一只股票可以买卖多次,所以当第 i 天买入股票的时候,所持有的现金需要考虑之前买卖过的利润
  • 可能是在第 i - 1 天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金,即:dp[i - 1][1](昨天持有股票)

因为求的最多现金,即 dp[i][1] = max(dp[i - 1][0] - prices[i], dp[i - 1][1])  

3、dp 数组初始化

从递推公式看出,求某一天 dp 需要知道其前一天的 dp 值,即都是要从dp[0][0]和dp[0][1]推导出来

那么dp[0][0]表示第 0 天未持有股票,不持有股票现金就是 0,所以 dp[0][0] = 0

dp[0][1]表示第 0 天持有股票,持有股票一定是在第 0 天买入了股票,所以 dp[0][1] = -prices[0]

4、确定遍历顺序

从递推公式可以看出 dp[i] 都是由 dp[i - 1] 推导出来的,那么一定是从前向后遍历

5、打印 dp 数组验证

代码如下:

class Solution {
public:
    int maxProfit(vector<int>& prices) {

        if (prices.size() == 0 || prices.size() == 1) return 0;
        
        // 定义dp数组下标及值含义
        vector<vector<int> > dp(prices.size(), vector<int>(2));
        
        // 确定递推公式:dp[i][0]和dp[i][1]分别确定

        // dp数组初始化,仅初始化第一天即可
        dp[0][0] = 0;
        dp[0][1] = -prices[0];

        // 从前往后遍历,一行一行填充
        for (int i = 1; i < prices.size(); ++i) {
            dp[i][0] = max(dp[i - 1][1] + prices[i], dp[i - 1][0]);
            dp[i][1] = max(dp[i-1][0] - prices[i], dp[i - 1][1]);
        }

        // 最后一定卖了才能取得最大
        return dp[prices.size() - 1][0];
    }
};

同样,能够通过滚动数组优化

class Solution {
public:
    int maxProfit(vector<int>& prices) {

        if (prices.size() == 0 || prices.size() == 1) return 0;
        
        // 滚动数组仅需维护原dp数组一行(一天)的数据
        int dp[2];
        
        // dp数组初始化,仅初始化原dp数组第一行(第一天)即可
        dp[0] = 0;
        dp[1] = -prices[0];

        // 一行一行遍历填充
        for (int i = 1; i < prices.size(); ++i) {
            dp[0] = max(dp[1] + prices[i], dp[0]);
            dp[1] = max(dp[0] - prices[i], dp[1]);
        }

        // 最后一定卖了才能取得最大
        return dp[0];
    }
};

回顾总结 

关键是需要明确 dp 数组的含义:用第二维区分持有股票和不持有股票的状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/558187.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

煤矿电子封条智能监管系统 TensorFlow

煤矿电子封条智能监管系统基于TensorFlowAI开源的机器学习的框架&#xff0c;煤矿电子封条智能监管系统可以对设备及人员行为和穿戴着装进行实时监测和管理。相比于其他的机器学习框架&#xff0c;Tensorflow 框架是最适用于工业部署的一个机器学习框架&#xff0c;换句话说&am…

数链科技用飞桨和文心大模型打造大宗商品数字供应链系统,提升行业透明度及标准化

大宗商品行业市场规模巨大、关系国计民生&#xff0c;它的三个核心类别——能源商品、基础原材料、农副产品均在我国经济发展进程中起着举足轻重的作用。这其中&#xff0c;大宗商品供应链的顺畅运行和稳定发展对整个产业链的运作至关重要。 然而传统大宗商品供应链普遍存在交易…

测试的正向思维和反向思维

测试的正向思维和反向思维 正向思维和反向思维是两种不同的思考方式&#xff0c;它们在决策和问题解决中起着重要的作用。 正向思维指的是以积极、乐观的态度看待事情&#xff0c;从优点出发&#xff0c;寻找解决问题的方法和途径。正向思维的人通常更容易接受挑战&#xff0c;…

Guitar Pro8最新五线谱转六线谱软件

提到吉他谱的编写&#xff0c;有一款软件总是被第一时间想到&#xff0c;那就是Guitar Pro。 Guitar Pro8所开启的音乐未来&#xff0c;不仅仅是一种全新的学习乐器方式。更在于对整个乐队的掌控&#xff0c;将弦乐的悠然和打击乐的劲爆尽收其间&#xff01; 同时&#xff0c;…

vmware安装debian 11.7.0

vmware安装debian 11.7.0 1、下载镜像2、创建并安装debian 11虚拟机2.1 选择 Graphical install2.2、选择安装过程显示语言和系统语言2.3、选择地区2.4、键盘映射2.5、设置主机名-debian2.6、设置网络-直接跳过2.7、设置root密码2.8、创建普通账户2.9、为普通账户设置密码2.10、…

ClickHouse:(一)安装部署

1.准备工作 1.2关闭防火墙 防火墙的开启、关闭、禁用命令 &#xff08;1&#xff09;设置开机启用防火墙&#xff1a;systemctl enable firewalld.service&#xff08;2&#xff09;设置开机禁用防火墙&#xff1a;systemctl disable firewalld.service&#xff08;3&#x…

VIBRO-METER VM600 AMC8 8个温度或过程监控通道

VM600 AMC8模拟监控卡 8个温度或过程监控通道每个通道1个已处理输出&#xff0c;每个多通道1个已处理输出(每个am c8 4个)高度可配置的卡支持使用热电偶和/或RTD进行温度监控&#xff0c;以及使用电流和/或电压输入进行过程监控高度集成的卡对(带IOC8T)包括DC输出、继电器和串行…

麒麟V10-arm安装conan

Conan基于Python编写&#xff0c;故需要在开始前安装好 Python3 一. 安装Python 1. 查看Python版本 python -v 若显示Python版本&#xff0c;则已安装&#xff0c;无需再次安装。若提示没有此命令(No command python found)&#xff0c;则表示没有安装Python。若Python版本过…

十五周算法训练营——快慢指针

今天是十五周算法训练营的第八周&#xff0c;主要讲快慢指针专题。&#xff08;欢迎加入十五周算法训练营&#xff0c;与小伙伴一起卷算法&#xff09; 移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数…

UDF提权(linux)

实验环境&#xff1a; RAVEN靶场&#xff1a;链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;g6oz 攻击机&#xff1a;kali 2023.3 IP&#xff1a;192.168.126.142 关于UDF提权&#xff0c;需要满足的条件是 1.数据库管理员权限运行 #如果权限过低&#xff…

安装docker compose

1.定义 Docker Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。通过 Compose&#xff0c;您可以使用 YML 文件来配置应用程序需要的所有服务&#xff0c;然后使用一个命令来创建并启动所有服务。Compose 有三个主要步骤&#xff1a; - 使用 Dockerfile 定义应用…

简历里项目经历怎么写,没有项目经历怎么办?

在撰写简历时&#xff0c;项目经历是一个非常重要的部分&#xff0c;能够有效地展示个人的能力和经验。但是&#xff0c;如果你没有项目经历怎么办呢&#xff1f;以下是一些关于如何写简历项目经历的建议&#xff0c;以及如何克服没有项目经历的挑战。 一、如何写简历项目经历 …

史上最详细的RACI(责任分配矩阵)使用方法及实例详解

作为PMO和项目经理一定对于RACI责任分配矩阵不陌生&#xff0c;但是很少有人真正用起来&#xff0c;RACI是一个广泛应用于项目管理的模型&#xff0c;用于明确角色和责任。 在项目的不同阶段或任务中&#xff0c;RACI模型有助于划分和理解团队成员的责任。今天咱们就为大家详细…

R语言绘制山脊图(也叫峰峦图、山峦图)

山脊图也叫也叫峰峦图、山峦图&#xff0c;主要是通过展示一个相同的X轴数据&#xff0c;可以是时间序列、基因数据等&#xff0c;对应不同的Y轴数据&#xff0c;清晰的展示不同数据见变量的关系。今天我们通过R语言来演示山脊图。需要使用到ggridges包&#xff0c;需要提前安装…

Hive ---- 查询

Hive ---- 查询 1. 基础语法2. 基本查询&#xff08;Select…From&#xff09;1. 数据准备2. 全表和特定列查询3. 列别名4. Limit语句5. Where语句6. 关系运算函数7. 逻辑运算函数8. 聚合函数 3. 分组1. Group By语句2. Having语句 4. Join语句1. 等值Join2. 表的别名3. 内连接…

vue:el-table初始化表格选中项踩坑记录/element-ui表格

问题描述 首先&#xff0c;element-ui表格多选功能可以参考官网示例&#xff1a;表格数据多选&#xff1b;手动在表格中选取数据、通过监听selection-change获取选中项&#xff0c;实现起来非常顺利~ 但在保存了选项、重新加载表格时&#xff0c;希望将已选项“打勾”却完全没…

这篇文章告诉你excel批量翻译有什么方法

在商业或个人领域中&#xff0c;我们有时需要将大量文本翻译成不同语言&#xff0c;例如跨国企业需要在不同的国家和地区之间进行文件传输和协作&#xff0c;在旅行时我们需要阅读当地语言的信息或地图。如果我们手动操作的话&#xff0c;是非常耗时且容易出错的&#xff0c;所…

知识管理、文档管理两手抓,全靠它!

知识管理和文档管理是两个相互关联的概念&#xff0c;两者之间的关系非常密切。知识管理是指对组织内外的知识资源进行收集、整理、存储、共享和应用的过程&#xff0c;旨在提高组织的绩效和创新能力。而文档管理是指对组织内外的文档资源进行收集、整理、存储、共享和应用的过…

chatgpt赋能Python-python_heading__

Python heading()方法&#xff1a;提高网页的SEO效果 介绍 在网页开发过程中&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;是一个重要的考虑因素。网页的排名和可见性对于用户的访问和广告收益非常重要。好的SEO可以大大提高网页的可见性和流量。因此&#xff0c;网页…

SolVES模型生态系统服务功能社会价值评估

查看原文>>>SolVES 模型生态系统服务功能社会价值评估&#xff08;基于多源环境QGIS、PostgreSQL、ArcGIS、Maxent、R语言&#xff09; 目录 第一章、理论基础与研究热点 第二章、SolVES 4.0 模型运行环境配置 第三章、SolVES 4.0 模型运行 第四章、数据获取与入…