LeetCode刷题复盘笔记—一文搞懂动态规划之121. 买卖股票的最佳时机问题(动态规划系列第二十篇)

news2024/10/6 6:43:40

今日主要总结一下动态规划的一道题目,121. 买卖股票的最佳时机

题目:121. 买卖股票的最佳时机

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

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

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

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

提示:

1 <= prices.length <= 105
0 <= prices[i] <= 104

方法一、贪心算法

首先这道题目可以用贪心算法来解决:
因为股票就买卖一次,那么贪心的想法很自然就是取最左最小值,取最右最大值,那么得到的差值就是最大利润。

C++代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int res = 0;
        int lowPrice = INT_MAX;
        for(int i = 0; i < prices.size(); i++){
            lowPrice = min(lowPrice, prices[i]);
            res = max(res, prices[i] - lowPrice);
        }
        return res;
    }
};

本题重难点

在买卖股票的最佳时机问题的整个系列题目中使用贪心算法仅仅可以解决某个具体场景的问题,但是并不通用,而动态规划思想解决买卖股票的最佳时机整个系列问题是通用连续递进的!

动规五部曲分析如下:

  1. 确定dp数组(dp table)以及下标的含义
    dp[i][0] 表示第i天持有股票所得最多现金 ,这里可能有同学疑惑,本题中只能买卖一次,持有股票之后哪还有现金呢?
    其实一开始现金是0,那么加入第i天买入股票现金就是 -prices[i], 这是一个负数。
    dp[i][1] 表示第i天不持有股票所得最多现金
    注意这里说的是“持有”,“持有”不代表就是当天“买入”!也有可能是昨天就买入了,今天保持持有的状态

    很多同学把“持有”和“买入”没分区分清楚。
    在下面递推公式分析中,我会进一步讲解。

  2. 确定递推公式
    如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来
    第i-1天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]
    第i天买入股票,所得现金就是买入今天的股票后所得现金即:-prices[i]
    那么dp[i][0]应该选所得现金最大的,所以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]取最大的,dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
    这样递归公式我们就分析完了

  3. dp数组如何初始化
    由递推公式 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[0][0]和dp[0][1]推导出来。
    那么dp[0][0]表示第0天持有股票,此时的持有股票就一定是买入股票了,因为不可能有前一天推出来,所以dp[0][0] -= prices[0];
    dp[0][1]表示第0天不持有股票,不持有股票那么现金就是0,所以dp[0][1] = 0;

  4. 确定遍历顺序
    从递推公式可以看出dp[i]都是有dp[i - 1]推导出来的,那么一定是从前向后遍历。

  5. 举例推导dp数组

以示例1,输入:[7,1,5,3,6,4]为例,dp数组状态如下:
在这里插入图片描述

方法二、 动态规划未优化代码

C++代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        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], - prices[i]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
        }
        return dp[prices.size() -  1][1];
    }
};

方法三、 动态规划优化代码

从递推公式可以看出,dp[i]只是依赖于dp[i - 1]的状态。
那么我们只需要记录 当前天的dp状态和前一天的dp状态就可以了,可以使用滚动数组来节省空间,代码如下:

C++代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < prices.size(); i++) {
            dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]);
            dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
        }
        return dp[(prices.size() - 1) % 2][1];
    }
};

总结

动态规划
英文:Dynamic Programming,简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。
动态规划中每一个状态一定是由上一个状态推导出来的,这一点就区分于贪心,贪心没有状态推导,而是从局部直接选最优的

对于动态规划问题,可以拆解为如下五步曲,这五步都搞清楚了,才能说把动态规划真的掌握了!

  1. 确定dp数组(dp table)以及下标的含义
  2. 确定递推公式
  3. dp数组如何初始化
  4. 确定遍历顺序
  5. 举例推导dp数组

这篇文章主要总结了一些动态规划解决121. 买卖股票的最佳时机问题,依然是使用动规五部曲,做每道动态规划题目这五步都要弄清楚才能更清楚的理解题目!

在买卖股票的最佳时机问题的整个系列题目中使用贪心算法仅仅可以解决某个具体场景的问题,但是并不通用,而动态规划思想解决买卖股票的最佳时机整个系列问题是通用连续递进的,最好掌握一下,并且最后给出了使用滚动数组优化空间复杂度的代码!
欢迎大家关注本人公众号:编程复盘与思考随笔
(关注后可以免费获得本人在csdn发布的资源源码)

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

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

相关文章

QML入门教程:QML和QtQuick简介以及QML实例

从 Qt 4.7 开始&#xff0c;Qt 引入了一种声明式脚本语言&#xff0c;称为 QML&#xff08;Qt Meta Language 或者 Qt Modeling Language&#xff09;&#xff0c;作为 C 语言的一种替代。而 Qt Quick 就是使用 QML 构建的一套类库。 QML 是一种基于 JavaScript 的声明式语言。…

激光焊接3系铝合金的工艺分析

随着汽车行业的不断壮大&#xff0c;纯电动汽车和燃料电池汽车将共同主导中国新能源汽车市场的未来发展。电动车轻量化和燃料电池的大量使用&#xff0c;必然涉及到越来越多的铝合金焊接工艺。铝合金具有良好的物理、化学和机械性能&#xff0c;是工业生产中一种重要的轻金属材…

搜索引擎搜索特定网站的方法 :site

前言 从13开始的贴吧时代&#xff0c;还记得当时在贴吧里要搜索某些特定的帖子或者关键字的时候&#xff0c;用的都是“吧内搜索”&#xff0c;但用过的人都知道&#xff0c;这个所谓的吧内搜索其实很难用&#xff0c;大家都是用关键字空格贴吧之类的办法去搜索相关的内容。我…

2025年350万辆市场空间!舱驾一体「抢」行泊/舱泊风头

过去三年是汽车智能化「细分作战」阶段&#xff0c;无论是智能驾驶还是智能座舱&#xff0c;由于品牌、车型定位不同&#xff0c;导致在不同价位区间、不同品牌、不同车型&#xff0c;舱内舱外智能化功能组合并不一致。 而随着跨域融合、中央计算平台带动汽车行业进入新的增长…

《树莓派项目实战》第九节 使用PCF8591模块和光敏电阻传感器测量光照强度

目录 8.1 PCF8691模块引脚介绍 8.2 工作原理 8.3 开启I2C接口 8.4 连接到树莓派 8.5 编写代码测量光照强度 在上一节我们使用光敏电阻传感器检测了环境中的光照是否达到了设定的阈值。在本节&#xff0c;我们将使用PCF8591模块和光敏电阻度传感器测量环境中光照强度的具体…

Continua CI捆绑的PostgreSQL数据库服务

Continua CI捆绑的PostgreSQL数据库服务 捆绑的PostgreSQL数据库服务已升级到15.1版。 现在可以使用表达式和变量在“配置存储库分支映射”对话框中为每个存储库指定默认分支。 在“停止”操作中添加了“将失败视为错误”选项。如果选中此项并且该操作位于“Try”块内&#xff…

Qt 模型视图编程之可编辑数据模型

背景 Qt 模型视图编程中模型定义了标准接口对数据进行访问&#xff0c;可根据需求继承对应的抽象模型类来实现自定义的数据模型。一个基本的数据模型至少要实现以下虚函数&#xff1a; ①&#xff0e;rowCount&#xff1a;行数&#xff0c;返回要显示多少行&#xff1b; ②&…

SpringBoot+Vue实现在线电子小说网站

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue.js 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JD…

伙伴福利,100个项目彻底精通Java!【开源】

为了帮助更多的小伙伴&#xff0c;快速成长进步&#xff0c;冲进大厂中厂&#xff0c;我分享了很多的项目哟&#xff0c;例如&#xff1a; java项目精品实战案例 | JavaSwing实战项目 但很多小伙伴&#xff0c;还觉得不够&#xff0c;好吧&#xff01;今天就拿出压箱底的项目…

CPU工作原理概述

为了了解CPU的完整工作过程&#xff0c;我们需要知道两件事&#xff0c;第一&#xff0c;CPU是如何获取到数据或者指令的&#xff1b;第二&#xff0c;CPU是如何执行指令的。 目录 一、CPU和内存的交互方式 1、地址空间的概念 2、CPU的取值过程 二、CPU内部的执行过程 1、…

OceanBase-安装

文章目录部署规划机器准备统一配置hosts设置设置机器名和静态ip关闭大页配置信息查看时钟源ntp配置&#xff08;需要所有机器root&#xff09;磁盘规划创建用户配置limits.conf配置sysctl.conf关闭防火墙关闭SELinux克隆虚拟机差异化配置中控机设置无密码SSH登录目标机器时钟源…

【推送位置苹果群发iMessage推】如果Windows和Linux实现不同的传输层协议,那末因为数据格式的不同

推荐内容IMESSGAE相关 作者推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者推荐内容3.日历推 *** 点击即可查看作者要求内容信息作者推荐…

Qt-Web混合开发-QWebEngineView加载网页最小示例(2)

Qt-Web混合开发-QWebEngineView加载网页最小示例 2&#x1f30d; 文章目录Qt-Web混合开发-QWebEngineView加载网页最小示例 2&#x1f30d;1、概述&#x1f310;2、实现效果&#x1f9ed;3、实现功能&#x1f685;4、关键代码&#x1f69a;5、源代码&#x1f680;更多精彩内容&…

高斯定理的理解——工程电磁场 P2~P5

证明&#xff1a;静电场是无旋场 根据斯托克斯公式上式等于 电位的引入 由于静电场是无源场&#xff0c;我们可以得到 又因为 再结合电场的物理意义&#xff0c;我们可以定义 功函数表达式的化简 原先功函数表达式 高斯定律的理解 不管是导体还是电解质&#xff0c;对于电…

【图像处理】FAST、BRIEF、ORB算法原理

整理FAST、BRIEF、ORB算法的原理。 FAST算法 一、FAST简介 FAST&#xff08;features from accelerated segment test&#xff09;是一种角点检测算法&#xff0c;可以用于提取特征点&#xff0c;后来也长用于目标跟踪等计算机视觉任务中。FAST角点检测算法最初由 Edward Ro…

LL(1)文法分析程序

一、实验目的 设计一个非递归预测分析器&#xff0c;实现对表达式语言的分析&#xff0c;理解自上而下语法 分析方法的基本思想&#xff0c;掌握设计LL&#xff08;&#xff09;文法分析程序设计的基本原理和方法。 根据给定LL&#xff08;1&#xff09;分析表&#xff0c;输入…

22-31-spark-核心编程-RDD概念及理解

22-spark-核心编程-RDD概念&#xff1a; 分布式计算基础测试&#xff1a; big-data-study\Spark-demo\src\main\java\spark\core\com\zh\test02 Spark 核心编程 Spark 计算框架为了能够进行高并发和高吞吐的数据处理&#xff0c;封装了三大数据结构&#xff0c;用于处理不同的…

vscode 离线安装ssh

首先打开官方插件地址&#xff1a;https://marketplace.visualstudio.com/VSCode 然后输入ssh 下载这两个插件&#xff1a; 安装这两个插件&#xff1a; 这样便在windows下安装成功了ssh。 接下来需要在服务器端进行配置。 首先查看windows上的vscode版本&#xff1a; 这…

Arduino 崩溃或挂起的 7 种方式及如何防止

Arduino 崩溃或挂起的 7 种方式&#xff08;以及如何防止它发生&#xff09; 作者&#xff1a;Chris in Arduino 查看原文 为了帮助防止Arduino崩溃或挂起&#xff0c;我进行了一系列实验&#xff0c;以确定Arduino崩溃&#xff0c;挂起&#xff0c;重置&#xff0c;冻结&am…

5.大型电商项目之创建前端展示模板并调用

1. templates前端模板的使用 1.1 templates前端模板的创建 首先&#xff0c;我们页面很多地方是相似的&#xff0c;这里就创建一个基础模板&#xff0c;不同的地方&#xff0c;对模板内容的block进行修改即可&#xff1b;对于相同的地方&#xff0c;我们就使用include包含即可…