【dp】买卖股票的最佳时机系列题目
文章目录
- 121. 买卖股票的最佳时机
- 122. 买卖股票的最佳时机 II
- 309. 最佳买卖股票时机含冷冻期
- 123. 买卖股票的最佳时机 III
- 188. 买卖股票的最佳时机 IV
121. 买卖股票的最佳时机
本题的重点是:只能在前面某一天买入,后面某一天卖出。要不就是不买入,收益为0
dp数组含义
本题两个状态:持有股票、不持有股票
- dp[i][1] :表示第i天持有股票所得最多现金
- dp[i][0] :表示第i天不持有股票所得最多现金
最后返回dp[n-1][0],表示最后一天不持有股票,所获得最多的现金
递推公式
第i天不持有股票所得最多现金 = max(第i-1天不持有股票手上的现金, 第i-1天手上持有股票、但是在第i天卖出手上的现金)
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
第i天持有股票手上的现金 = max(第i-1天持有股票手上的现金, 第i-1天手上没有股票、但是在第i天买入股票手上的现金)
dp[i][1] = max(dp[i-1][1], 0 - prices[i]) // i-1天不持有,第i天持有,那一定是第i天买入
初始化
- dp[0][0]:第0天不持有股票,所能获得的现金,就是0
- dp[0][1]:第0天持有股票,所能获得的现金,就是第0天买入股票后手上的钱,即 -prices[0]
class Solution {public:int maxProfit(vector<int>& prices) {int n = prices.size();// dp[i][1] 表示第i天持有股票所得最多现金// dp[i][0] 表示第i天不持有股票所得最多现金vector<vector<int>> dp(n, vector<int>(2, 0));dp[0][1] = 0 - prices[0]; // 第0天持有股票,手上的钱就是买入后的负数dp[0][0] = 0; // 第0天不持有股票,手上的钱是0 for(int i = 1; i < n; i++){// 第i天不持有股票所得最多现金 = max(第i-1天没有股票手上的现金, 第i-1天手上持有股票、但是在第i天卖出手上的现金)dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);// 第i天持有股票手上的现金 = max(第i-1天持有股票手上的现金, 第i-1天手上没有股票、但是在第i天买入股票手上的现金)dp[i][1] = max(dp[i-1][1], 0 - prices[i]); }return dp[n-1][0];}
};
第二种dp方法
第i天的最大收益 = max(第i-1天的最大收益,第i天的价格 - 前i-1天的最低价)
dp[i] = max(dp[i-1], prices[i] - min_val)
class Solution {public:int maxProfit(vector<int>& prices) {int n = prices.size();vector<int> dp(n, 0); // dp[i]:第i天的最大收益dp[0] = 0;int min_val = prices[0];for(int i = 1; i < n; i++){min_val = min(min_val, prices[i]);dp[i] = max(dp[i-1], prices[i] - min_val);}return dp[n-1];}
};
122. 买卖股票的最佳时机 II
本题的重点是:可以在任意一天进行买入或卖出,且不限制买入和卖出的次数
dp数组含义
本题两个状态:持有股票、不持有股票
- dp[i][1] :表示第i天持有股票所得最多现金
- dp[i][0] :表示第i天不持有股票所得最多现金
最后返回dp[n-1][0],表示最后一天不持有股票,所获得最多的现金
递推公式
第i天不持有股票所得最多现金 = max(第i-1天不持有股票手上的现金, 第i-1天手上持有股票、但是在第i天卖出手上的现金)
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
第i天持有股票手上的现金 = max(第i-1天持有股票手上的现金, 第i-1天手上没有股票、但是在第i天买入股票手上的现金)
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
初始化
- dp[0][0]:第0天不持有股票,所能获得的现金,就是0
- dp[0][1]:第0天持有股票,所能获得的现金,就是第0天买入股票后手上的钱,即 -prices[0]
class Solution {public:int maxProfit(vector<int>& prices) {int n = prices.size();// dp[i][1] 表示第i天持有股票手上最多的现金// dp[i][0] 表示第i天不持有股票所得最多现金vector<vector<int>> dp(n, vector<int>(2, 0));dp[0][1] = 0 - prices[0];dp[0][0] = 0;// dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])// dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])for(int i = 1; i < n; i++){dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]);}return dp[n-1][0];}
};
直接把价格上升的部分累加即可
class Solution {public:int maxProfit(vector<int>& prices) {int n = prices.size();int ans = 0;for(int i = 1; i < n; i++){if(prices[i] > prices[i-1]) ans += prices[i] - prices[i-1];}return ans;}
};
309. 最佳买卖股票时机含冷冻期
本题就是在122. 买卖股票的最佳时机 II的基础上加上了冷冻期
122. 买卖股票的最佳时机 II有两个状态:持有股票后的最多现金,和不持有股票的最多现金
而本题中,我们将状态分为三种:持有股票、不持有股票处于冷冻期、不持有股票不处于冷冻期
dp数组含义
- dp[i][0]:不持有股票,不在冷冻期,能获得的最大收益
- dp[i][1]:不持有股票,在冷冻期,能获得的最大收益
- dp[i][2]:持有股票,能获得的最大收益
递推公式
第i天不持有股票,且不在冷冻期能获得的最大收益 = max(前一天处于冷冻期的收益,前一天不持有股票且不在冷冻期的收益)
dp[i][0] = max(dp[i-1][1], dp[i-1][0])
第i天不持有股票,且在冷冻期能获得的最大收益 = 前一天持有股票卖出的收益
dp[i][1] = dp[i-1][2] + prices[i]
第i天持有股票能获得的最大收益 = max(前一天持有股票没卖,前一天不持有股票且不在冷冻期但是买入股票)
dp[i][2] = max(dp[i-1][2], dp[i-1][0] - prices[i])
初始化
- dp[0][0] = 0:不持有股票,不在冷冻期
- dp[0][1] = 0:不持有股票,在冷冻期
- dp[0][2] = 0 - prices[0]:持有股票,第0天买入即可
class Solution {public:int maxProfit(vector<int>& prices) {int n = prices.size();vector<vector<int>> dp(n, vector<int>(3, 0));dp[0][0] = 0; // 不持有股票,不在冷冻期dp[0][1] = 0; // 不持有股票,在冷冻期dp[0][2] = 0 - prices[0]; // 持有股票for(int i = 1; i < n; i++){dp[i][0] = max(dp[i-1][1], dp[i-1][0]);dp[i][1] = dp[i-1][2] + prices[i];dp[i][2] = max(dp[i-1][2], dp[i-1][0] - prices[i]);}return max(dp[n-1][0], dp[n-1][1]);}
};
123. 买卖股票的最佳时机 III
一天一共就有五个状态:
- 未操作过
- 处于第一次持有股票的状态
- 处于第一次持有股票、又卖出的状态
- 处于第二次持有股票的状态
- 处于第二次不持有股票、又卖出的状态
dp数组含义
dp[i][j]:表示第i天,处于状态j时,所能获得的最大收益
- dp[i][0]:没买卖过股票,所能获得的最大收益
- dp[i][1]:处于第一次持有股票的状态,所能获得的最大收益
- dp[i][2]:处于第一次持有股票、又卖出的状态,所能获得的最大收益
- dp[i][3]:处于第二次持有股票的状态,所能获得的最大收益
- dp[i][4]:处于第二次不持有股票、又卖出的状态,所能获得的最大收益
递推公式
状态0:没买卖过股票
很明显,图中没有入度,无需更新,所能获得的最大收益保持为0
状态1:第一次持有股票
第一次处于持有股票状态的最大收益 = max(前一天就处于第一次持有股票状态, 前一天没做操作、今天才买入股票)
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
状态2:第一次持有股票、又卖出
第一次处于持有股票、又卖出状态的最大收益 = max(前一天就处于第一次持有股票、又卖出状态, 前一天处于持有股票、今天才卖出)
dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
状态3:第二次持有股票
第二次处于持有股票状态的最大收益 = max(前一天就处于第二次持有股票状态, 前一天处于第一次持有股票并卖出、今天才买入股票)
dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])
状态4:第二次不持有股票、又卖出
第二次处于持有股票、又卖出状态的最大收益 = max(前一天就处于第二次持有股票、又卖出状态, 前一天处于第二次持有股票、今天才卖出)
dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])
初始化
- dp[0][0]:第0天没操作,收益为0
- dp[0][1]:第0天买入,收益为-prices[0]
- dp[0][2]:第0天买入后卖出,收益为0
- dp[0][3]:第0天买入后卖出,再买入,收益为-prices[0]
- dp[0][4]:第0天买入后卖出,再买入卖出,收益为0
class Solution {public:int maxProfit(vector<int>& prices) {int n = prices.size();vector<vector<int>> dp(n, vector<int>(5, 0));dp[0][1] = 0 - prices[0];dp[0][3] = 0 - prices[0];for(int i = 1; i < n; i++){dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]);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[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i]);}return dp[n-1][4];}
};
观察可以发现,二维数组中,计算当前层数据时,只需要使用上方元素,以及上方相邻元素即可,和背包问题压缩维度原理一样,本题也可以压缩维度,逆序更新即可。因为计算下一行时,没有用到后面的元素,先更新后面的没有影响
其实本题不改变更新顺序也行
class Solution {public:int maxProfit(vector<int>& prices) {int n = prices.size();vector<int> dp(5, 0);dp[1] = 0 - prices[0];dp[3] = 0 - prices[0];for(int i = 1; i < n; i++){dp[4] = max(dp[4], dp[3] + prices[i]);dp[3] = max(dp[3], dp[2] - prices[i]);dp[2] = max(dp[2], dp[1] + prices[i]);dp[1] = max(dp[1], dp[0] - prices[i]); }return dp[4];}
};
188. 买卖股票的最佳时机 IV
上题中,最多两笔交易时,有5个状态;本题最多k笔交易,会有2*k+1个状态,因为完成k笔交易,需要k次买入和k次卖出,再加上不做任何操作的状态,总共有2*k+1个状态
和上题一样,我们把除了0以外的奇数状态定为持有股票状态,而偶数状态定为卖出股票的状态
dp数组含义
dp[i][j]:表示第i天,处于状态j时,所能获得的最大收益,强调一下,第i天可以经过多种状态,因为不限制每天卖卖股票的次数,就像下面初始化时所描述的一样
初始化
- dp[0][0]:第0天没操作,收益为0
- dp[0][1]:第0天买入,收益为-prices[0]
- dp[0][2]:第0天买入后卖出,收益为0
- dp[0][3]:第0天买入后卖出,再买入,收益为-prices[0]
- dp[0][4]:第0天买入后卖出,再买入卖出,收益为0
- …
我们可以看出,奇数状态为买入状态,统一初始化为-prices[0],偶数状态为0
class Solution {public:int maxProfit(int k, vector<int>& prices) {int n = prices.size();vector<vector<int>> dp(n, vector<int>(2 * k + 1, 0));for(int i = 1; i < 2 * k + 1; i += 2){dp[0][i] = 0 - prices[0];}for(int i = 1; i < n; i++){for(int j = 1; j < 2 * k + 1; j++){if(j & 1) dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] - prices[i]);else dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] + prices[i]);}}return dp[n-1][2*k];}
};
压缩维度
class Solution {public:int maxProfit(int k, vector<int>& prices) {int n = prices.size();vector<int> dp(2 * k + 1, 0);for(int i = 1; i < 2 * k + 1; i += 2){dp[i] = 0 - prices[0];}for(int i = 1; i < n; i++){for(int j = 2 * k; j > 0; j--){if(j & 1) dp[j] = max(dp[j], dp[j-1] - prices[i]);else dp[j] = max(dp[j], dp[j-1] + prices[i]);}}return dp[2*k];}
};
【dp】买卖股票的最佳时机系列题目相关推荐
- LeetCode买卖股票的最佳时机系列总结
LeetCode买卖股票的最佳时机系列总结 此类动态规划从二维动规理解后优化到一维动规,部分题目还可以用到贪心. 目录: 121 买卖股票的最佳时机1 122 买卖股票的最佳时机2 123 买卖股票的 ...
- 买卖股票的最佳时机系列
买卖股票的最佳时机系列 1. 概述 2. dp 数组定义为状态 2.1 买卖股票的最佳时机 2.2 买卖股票的最佳时机 II 2.3 最佳买卖股票时机含冷冻期 2.4 买卖股票的最佳时机含手续费 3. ...
- “买卖股票的最佳时机” 系列——我来教你稳赚不亏~
目录 前言 一.买卖股票的最佳时机 -->指定次数交易(1次) 1.1.dp定义 1.2.递推公式 1.3.遍历顺序 1.4.初始化 1.5.解题代码 二.买卖股票的最佳时机II -->交 ...
- 第43天| 123.买卖股票的最佳时机III、 188.买卖股票的最佳时机IV
1.题目链接:123. 买卖股票的最佳时机 III 题目描述: 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你最多可以完成 两笔 交易 ...
- 【买卖股票的最佳时机】
[LeetCode121. 买卖股票的最佳时机] 题目描述 方法1: 一次遍历 方法2: 动态规划 题目描述 买卖股票的最佳时机 https://leetcode-cn.com/problems/be ...
- 算法训练第五十天 | 123.买卖股票的最佳时机III、188.买卖股票的最佳时机IV
动态规划part11 123.买卖股票的最佳时机III 题目描述 思路 拓展 188.买卖股票的最佳时机IV 题目描述 思路 易错点 123.买卖股票的最佳时机III 题目链接:123.买卖股票的最佳 ...
- _42LeetCode代码随想录算法训练营第四十二天-动态规划 | 121.买卖股票的最佳时机、122.买卖股票的最佳时机II
_42LeetCode代码随想录算法训练营第四十二天-动态规划 | 121.买卖股票的最佳时机.122.买卖股票的最佳时机II 题目列表 121.买卖股票的最佳时机 122.买卖股票的最佳时机II 1 ...
- 【2021/5/17 刷题笔记】买卖股票的最佳时机与动态规划
文章目录 买卖股票的最佳时机 [题目] [我的方法] 执行结果: 动态规划算法 1.状态定义 2.设置数组边界值 3.推导状态转换方程. 参考代码 执行结果: 复杂度分析: 时间复杂度 空间复杂度 * ...
- day49买卖股票的最佳时机12
力扣121.买卖股票的最佳时机1 题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/ ##思路 1.dp数组:用一个二 ...
最新文章
- 基因对智力的预测能力不到7%,别迷信它
- 技术方案——可控组播
- sdn和nfv的区别—Vecloud微云
- oracle 最近的sql语句,oracle最近执行的sql语句
- python 之configparser模块
- python基础学习1-内置函数
- 文本界面安装linux 7,安装 CentOS7 后必做的事 [最小化、文本界面]
- eclipse中启动tomcat的项目路径
- Eclipse搭建SSH环境实现Struts2分页显示mysql数据库表中内容
- 网页版excel服务器,用excel当数据库,做个简单的网页
- matlab动态更新数组值,Matlab动态数组实现
- 2018最新手机号码正则表达式
- iphonex时间显示蓝色_iphonex左上角时间蓝色
- Openbravo怎么给工具栏添加一个按钮
- 【无线电】无线电频谱和波段划分
- knuth的SJT实现
- Unity 组合键输入及容易忽略的问题
- docker_相关操作
- 亚信实习——初来乍到
- 计算机教学运用培训,教师计算机培训教学教程.doc
热门文章
- 数据库优化一般思路(个人经验之谈)
- 怎么看待新一代互联网的机遇?!
- Android Miracast 架构
- 报错urllib.error.URLError:urlopen error [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败
- 第12节:Sentinel入门安装+限流规则
- R语言使用glm函数构建泊松对数线性回归模型处理三维列联表数据构建饱和模型、使用step函数基于AIC指标实现逐步回归筛选最佳模型、使用summary函数查看简单模型的汇总统计信息
- linux为什么要磁盘限额,Linux磁盘限额
- 万能头文件的几个函数
- mysql影响行数解析_对PHP函数mysqli_affected_rows的作用行数返回值的分析
- 华为鸿蒙系统搭载机型,华为鸿蒙 2.0 首批升级机型曝光,快来看看你的机器在不在...