文章目录

  • 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】买卖股票的最佳时机系列题目相关推荐

  1. LeetCode买卖股票的最佳时机系列总结

    LeetCode买卖股票的最佳时机系列总结 此类动态规划从二维动规理解后优化到一维动规,部分题目还可以用到贪心. 目录: 121 买卖股票的最佳时机1 122 买卖股票的最佳时机2 123 买卖股票的 ...

  2. 买卖股票的最佳时机系列

    买卖股票的最佳时机系列 1. 概述 2. dp 数组定义为状态 2.1 买卖股票的最佳时机 2.2 买卖股票的最佳时机 II 2.3 最佳买卖股票时机含冷冻期 2.4 买卖股票的最佳时机含手续费 3. ...

  3. “买卖股票的最佳时机” 系列——我来教你稳赚不亏~

    目录 前言 一.买卖股票的最佳时机 -->指定次数交易(1次) 1.1.dp定义 1.2.递推公式 1.3.遍历顺序 1.4.初始化 1.5.解题代码 二.买卖股票的最佳时机II -->交 ...

  4. 第43天| 123.买卖股票的最佳时机III、 188.买卖股票的最佳时机IV

    1.题目链接:123. 买卖股票的最佳时机 III 题目描述: 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你最多可以完成 两笔 交易 ...

  5. 【买卖股票的最佳时机】

    [LeetCode121. 买卖股票的最佳时机] 题目描述 方法1: 一次遍历 方法2: 动态规划 题目描述 买卖股票的最佳时机 https://leetcode-cn.com/problems/be ...

  6. 算法训练第五十天 | 123.买卖股票的最佳时机III、188.买卖股票的最佳时机IV

    动态规划part11 123.买卖股票的最佳时机III 题目描述 思路 拓展 188.买卖股票的最佳时机IV 题目描述 思路 易错点 123.买卖股票的最佳时机III 题目链接:123.买卖股票的最佳 ...

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

    _42LeetCode代码随想录算法训练营第四十二天-动态规划 | 121.买卖股票的最佳时机.122.买卖股票的最佳时机II 题目列表 121.买卖股票的最佳时机 122.买卖股票的最佳时机II 1 ...

  8. 【2021/5/17 刷题笔记】买卖股票的最佳时机与动态规划

    文章目录 买卖股票的最佳时机 [题目] [我的方法] 执行结果: 动态规划算法 1.状态定义 2.设置数组边界值 3.推导状态转换方程. 参考代码 执行结果: 复杂度分析: 时间复杂度 空间复杂度 * ...

  9. day49买卖股票的最佳时机12

    力扣121.买卖股票的最佳时机1 题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/ ##思路 1.dp数组:用一个二 ...

最新文章

  1. 基因对智力的预测能力不到7%,别迷信它
  2. 技术方案——可控组播
  3. sdn和nfv的区别—Vecloud微云
  4. oracle 最近的sql语句,oracle最近执行的sql语句
  5. python 之configparser模块
  6. python基础学习1-内置函数
  7. 文本界面安装linux 7,安装 CentOS7 后必做的事 [最小化、文本界面]
  8. eclipse中启动tomcat的项目路径
  9. Eclipse搭建SSH环境实现Struts2分页显示mysql数据库表中内容
  10. 网页版excel服务器,用excel当数据库,做个简单的网页
  11. matlab动态更新数组值,Matlab动态数组实现
  12. 2018最新手机号码正则表达式
  13. iphonex时间显示蓝色_iphonex左上角时间蓝色
  14. Openbravo怎么给工具栏添加一个按钮
  15. 【无线电】无线电频谱和波段划分
  16. knuth的SJT实现
  17. Unity 组合键输入及容易忽略的问题
  18. docker_相关操作
  19. 亚信实习——初来乍到
  20. 计算机教学运用培训,教师计算机培训教学教程.doc

热门文章

  1. 数据库优化一般思路(个人经验之谈)
  2. 怎么看待新一代互联网的机遇?!
  3. Android Miracast 架构
  4. 报错urllib.error.URLError:urlopen error [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败
  5. 第12节:Sentinel入门安装+限流规则
  6. R语言使用glm函数构建泊松对数线性回归模型处理三维列联表数据构建饱和模型、使用step函数基于AIC指标实现逐步回归筛选最佳模型、使用summary函数查看简单模型的汇总统计信息
  7. linux为什么要磁盘限额,Linux磁盘限额
  8. 万能头文件的几个函数
  9. mysql影响行数解析_对PHP函数mysqli_affected_rows的作用行数返回值的分析
  10. 华为鸿蒙系统搭载机型,华为鸿蒙 2.0 首批升级机型曝光,快来看看你的机器在不在...