代码随想录算法训练营第五十二天_第九章_动态规划 | 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II

news2024/11/17 5:59:11
LeetCdoe 121. 买卖股票的最佳时机

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

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

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

视频讲解https://www.bilibili.com/video/BV1Xe4y1u77q 文章讲解https://www.bilibili.com/video/BV1Xe4y1u77q
  • 思路:涉及到买入 / 卖出,同一天手头金额会有变化,统一用 进行完买卖选择之后 的状态
    • dp[i] 表示第 i 天 结算后 的最大金额👉能否买入 / 卖出 依赖于前一天的状态(是否持有股票)👉dp[i][0]表示第 i 天 结算后 持有股票,dp[i][1]表示第 i 天 结算后 不持有股票
    • 递推公式:  
      • dp[i][0]表示第 i 天 结算后 持有股票的最大金额,有两个来源:
        1. 第 i - 1 天 结算后 就持有股票,第 i 天不卖出,即 dp[i - 1][0]
        2. 第 i - 1 天 结算后 不持有股票,而第 i 天买入,即 dp[i - 1][1] - prices[i]
      • 注:由于只能买入一次,如果第 i 天买入,那么 dp[i - 1][1] 一定是0,即 -prices[i]
      • dp[i][0] = max(dp[i - 1][0], -prices[i])
      • dp[i][1]表示第 i 天 结算后 不持有股票的最大金额,有两个来源:
        1. 第 i - 1 天 结算后 不持有股票,第 i 天也不买入,即 dp[i - 1][1]
        2. 第 i - 1 天 结算后 持有股票,但第 i 天将其卖出,即 dp[i - 1][0] + prices[i]
      • dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i])
    • 初始化:
      • 第 0 天 结算后 持有股票,即买入股票prices[0]👉dp[0][0] = -prices[0]
      • 第 0 天 结算后 不持有股票,即不买入股票prices[0]👉dp[0][1] = 0
    • 遍历顺序:从前向后
    • ⭐最终结果在dp[prices.size() - 1][1]:因为 dp[prices.size() - 1][0] 一定 <=0(相当于股票砸手里,还不如不买,不买是0)
  • 代码:
// 贪心:取最左最小值,取最右最大值,那么得到的差值就是最大利润
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int low = INT_MAX;
        int result = 0;
        for (int i = 0; i < prices.size(); i++) {
            low = min(low, prices[i]);  // 取最左最小价格
            result = max(result, prices[i] - low); // 直接取最大区间利润
        }
        return result;
    }
};
// 动态规划:版本一
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        if (len == 0) return 0;
        vector<vector<int>> dp(len, vector<int>(2));
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; 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[len - 1][1];
    }
};
// 时间复杂度:O(n)
// 空间复杂度:O(n)
// 动态规划:版本二(滚动数组)
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; 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[(len - 1) % 2][1];
    }
};
// 时间复杂度:O(n)
// 空间复杂度:O(1)

// 自己:最多买一次、卖一次,故dp0不依赖于前一天的dp1,可先更新dp1(要依赖于前一天的dp0),后更新dp0
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int dp0 = -prices[0];   // 持有股票
        int dp1 = 0;    // 不持有股票
        for (int i = 1; i < prices.size(); ++i) {
            dp1 = max(dp1, dp0 + prices[i]); // 买入一定在卖出之前
            dp0 = max(dp0, -prices[i]); // 要买就买最便宜的那支
        }
        return dp1;
    }
};

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

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

        设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

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

视频讲解https://www.bilibili.com/video/BV1D24y1Q7Ls文章讲解https://programmercarl.com/0122.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAII%EF%BC%88%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%EF%BC%89.html

  • 思路:题中说“可以先购买,然后在同一天出售”,不管先买后卖还是先卖后买,从 结算后 持有股票状态金额 来看相当于 没买没卖。
    • dp数组含义:
      • dp[i][0] 表示 第i天 结算后 持有股票 所得最大金额
      • dp[i][1] 表示 第i天 结算后 不持有股票 所得最大金额
    • 递推公式:
      • dp[i][0]:第i天 结算后 持有股票
        1. 第i - 1天结算后就持有股票
        2. 第i - 1天结算后不持有股票,以 prices[i] 买入
      • dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i])
      • 注:由于可以买入多次,如果第 i 天买入,那么 dp[i - 1][1]不一定是0
      • dp[i][1]:第i天 结算后 不持有股票
        1. 第i - 1天结算后就不持有股票
        2. 第i - 1天结算后持有股票,以 prices[i] 卖出
      • dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
    • 初始化:dp[0][0] = -prices[0],其余值全0
    • 遍历顺序:从前向后
    • ⭐最终结果在dp[prices.size() - 1][1]:因为 dp[prices.size() - 1][0] 一定 <= dp[x][1] <= dp[prices.size() - 1][1](相当于股票砸手里,还不如不买这支股票
  • 代码:
// 动态规划:版本一
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>> dp(len, vector<int>(2, 0));
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; i++) {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); // 注意这里是和121. 买卖股票的最佳时机唯一不同的地方。
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
        }
        return dp[len - 1][1];
    }
};
// 时间复杂度:O(n)
// 空间复杂度:O(n)
// 动态规划:版本二(滚动数组)
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int len = prices.size();
        vector<vector<int>> dp(2, vector<int>(2)); // 注意这里只开辟了一个2 * 2大小的二维数组
        dp[0][0] -= prices[0];
        dp[0][1] = 0;
        for (int i = 1; i < len; i++) {
            dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] - prices[i]);
            dp[i % 2][1] = max(dp[(i - 1) % 2][1], prices[i] + dp[(i - 1) % 2][0]);
        }
        return dp[(len - 1) % 2][1];
    }
};
// 时间复杂度:O(n)
// 空间复杂度:O(1)
// 自己:dp0依赖于前一天的dp0, dp1而dp1依赖于前一天的dp0, dp1
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int dp0 = -prices[0]; // 持有股票
        int dp1 = 0; // 不持有股票
        int tmp = 0; // 记录前一天的dp1,用于dp0的计算
        for (int i = 1; i < prices.size(); ++i) {
            dp1 = max(dp1, dp0 + prices[i]);
            dp0 = max(dp0, tmp - prices[i]);
            tmp = dp1; //用于下一天dp0的计算
        }
        return max(dp0, dp1);
    }
};

思考:这道题确实贪心解法简洁很多,但贪心需要具体问题具体分析,而动态规划整体框架固定,解决股票全家桶也不在话下。

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

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

相关文章

verilog 数字系统设计读书笔记-------持久更新

Verilog模型可以是实际电路的不同级别的抽象。这些抽象的级别和它们所对应的模型类型共有以下5种&#xff1a;系统级、算法级、RTL级、门级、开关级‘bz :表示高阻态&#xff0c; ’bx表示不定值&#xff08;0或1均可&#xff09;include "muxtwo.v" 将文件引进{$ ra…

【Linux】怎么理解进程

✍作者&#xff1a;阿润菜菜 &#x1f4d6;专栏&#xff1a;Liunx系统编程 本文通过冯诺依曼体系结构&#xff08;硬件部分&#xff09;和操作系统&#xff08;软件部分&#xff09;为基础来介绍我们应该如何理解进程&#xff0c;为后续的学习做铺垫。 本文目录一、预备知识1.建…

误差逆传播算法公式理解及推导

前言&#xff1a;公式理解及推导参考自《机器学习》周志华 P101 BP网络 BP网络一般是指由 误差逆传播&#xff08;error BackPropagation, BP&#xff09;算法训练的多层前馈神经网络。 给定训练集 D{(x1,y1)D\left\{\left(\boldsymbol{x}_1, \boldsymbol{y}_1\right)\right…

2023年我的Flag已准备完毕

前言&#xff1a; &#x1f604;作者简介&#xff1a;小曾同学.com,小伙伴们也可以叫我小曾&#xff0c;一个致力于测试开发的博主⛽️ 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a…

用力过猛,把服务压挂了?

背景 在刚开始进行压测的时候&#xff0c;我也不知道需要提前分析下压测的QPS目标&#xff0c;也不知道说第一步压测的预估值是多少&#xff0c;结果一下子干上去&#xff0c;就把测试环境的服务给整挂了&#xff0c;然后就迎来了一大波的投诉&#xff08;好惨呐&#xff09…

【6-循环神经网络】北京大学TensorFlow2.0

课程地址&#xff1a;【北京大学】Tensorflow2.0_哔哩哔哩_bilibiliPython3.7和TensorFlow2.1六讲&#xff1a;神经网络计算&#xff1a;神经网络的计算过程&#xff0c;搭建第一个神经网络模型神经网络优化&#xff1a;神经网络的优化方法&#xff0c;掌握学习率、激活函数、损…

基于微信小程序的校园自助打印系统小程序

文末联系获取源码 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7/8.0 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.3.…

GJB 5000B二级-RDM需求开发与管理

一、主要变化情况 新增3项(金色)、合并12->5项(绿色)、修订3项(蓝色) 合并的主要内容 1、合并过程域:原标准中RD与ReqM合并为RDM   需求开发与需求管理的过程活动紧密相关,在全生命周期中不可分割。 2、合并实践条目:精炼实践,聚焦重点   a)ReqM SP1.1“获…

UE运行时动态设置屏幕分辨率

文章目录 1.实现目标2.实现过程2.1 控制台直接输入命令2.2 通过蓝图设置3.参考资料1.实现目标 在UE中以独立进程(Standalone Game)方式启动游戏,并在运行时动态修改游戏窗口的屏幕分辨率大小,如下图所示屏幕大小从1000x800修改为600x400。 2.实现过程 参考文档和资料,通…

微服务服务治理

服务治理什么是服务治理&#xff1f;第一部分 服务注册第二部分 服务发现Nacos(常见注册中心)入门搭建Nacos环境Nacos远程调用实现商品服务的负载均衡什么是负载均衡&#xff1f;手动实现负载均衡利用组件实现负载均衡修改负载均衡策略什么是服务治理&#xff1f; 服务治理是微…

PySpark sql 中一些函数的总结(持续更新)

看到什么函数就记录了&#xff0c;没有什么逻辑关系 spark 中DataFrame 和 pandas的DataFrame的区别 1. F.split() 和 df.withColumn() from pyspark.sql import SparkSession from pyspark.sql import functions as F from pyspark.sql.types import *df spark.sql(sql) sp…

打开Jupyter notebook没有虚拟环境内核

放了个假&#xff0c;今天准备打开anaconda中的jupyter notebook重温一下之前的文档&#xff0c;结果双击Anaconda-Navigator出现了【应用程序“Anaconda-Navigator”无法打开】&#xff0c;想着利用终端也可以操作&#xff0c;于是使用下面命令激活了环境并打开jupter noteboo…

JZ11 旋转数组的最小数字

【答案解析】&#xff1a;暴力破解&#xff1a;遍历数组找出最小值即可 更优思想&#xff1a;采用二分查找&#xff0c;这个题主要分析三种旋转情况[1, 2, 3, 4, 5]&#xff0c;使用中间值与右端进行比较。 1. 中间大于右边[3, 4, 5, 1, 2]&#xff0c;这种情况下&#xff0c;最…

Spring Framework-01

Spring两大核心技术 1.IOC 2.AOP Spring 1 Spring Framework 1.核心层 Core Container:核心容器&#xff0c;这个模块是Spring最核心的模块&#xff0c;其他的都需要依赖该模块 2.AOP层 AOP:面向切面编程&#xff0c;它依赖核心层容器&#xff0c;目的是在不改变原有代码的前…

国内那么多的低代码平台,究竟哪家比较强?

国内有特色的低代码快速开发平台产品有哪些&#xff1f;这篇就来介绍下目前市面上主要的几家低代码开发平台&#xff01; 简道云、明道云、IVX这几家目前是无代码赛道的明星选手&#xff0c;在市场综合表现上名列前茅。宜创、红圈营销虽也极具潜力&#xff0c;但在市场表现力上…

virsh日常管理命令

virsh日常管理命令virsh日常管理命令创建vm实例规范网卡编号从0开始Centos7最小化安装环境勾选VM实例建议只分配/分区查看vm列表启动vm实例--startvm实例(软)关机--shutdownvm实例断电关机--destroyvm实例(软)重启--rebootvm实例重命名--domrenamevm实例挂起--suspend查看vm实例…

Elasticsearch:从 Kafka 到 Elasticsearch 的实时用户配置文件数据管道

如今&#xff0c;网络服务、数字媒体、传感器日志数据等众多来源产生了大量数据&#xff0c;只有一小部分数据得到妥善管理或利用来创造价值。读取大量数据、处理数据并根据这些数据采取行动比以往任何时候都更具挑战性。 在这篇文章中&#xff0c;我试图展示&#xff1a; 在…

Discord教程:Discord账号注册、Discord多账号登录和管理

Discord最初是为游戏玩家在群聊和交流而创建的。但自疫情爆发以来&#xff0c;许多企业、公司和初创公司发现&#xff0c;居家办公时使用Discord进行日常沟通非常便捷。 Discord不再是仅限于游戏玩家&#xff0c;平台建立了不同于其他任何社交空间的新空间&#xff0c;封闭又开…

9、矩阵的简单运算

目录 一、矩阵的加减运算 二、矩阵的乘方运算 1.数与矩阵的乘法 2.矩阵与矩阵的乘法 三、矩阵的除法 四、矩阵的幂运算 五、矩阵元素的查找 六、矩阵元素的排序 七、矩阵元素的求和 八、矩阵元素的求积 九、矩阵元素的差分 一、矩阵的加减运算 进行矩阵加法、减法运…

前端学习第四站——CSS全面学习基础篇

目录 一、基础认知 1.1 CSS的介绍 1.2 语法规则 1.3 CSS初体验 1.4 CSS初识-小结 2.1 CSS引入方式 二、基础选择器 1.1 选择器的作用 1.2 标签选择器 1.3. 类选择器 1.4 id选择器 补充&#xff1a;类和id的区别 1.5 通配符选择器 三、字体和文本样式 1. 字体样式 …