一、买卖股票的最佳时机 (LeetCode 121)

简单的动态规划问题,只能完成一次买卖,定义二维 dp[i] [] 数组,dp [i] [0]表示没有股票的状态,dp [i] [1]表示持有股票的状态,由于只能买卖一次股票所以 dp [i] [1]不受dp [i-1] [0]的影响

public int maxProfit(int[] prices) {int[][] dp = new int[prices.length][2];dp[0][0] = 0;dp[0][1] = -prices[0];for (int i = 1; i < prices.length; i++) {dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);dp[i][1] = Math.max(-prices[i],dp[i-1][1]);}return dp[prices.length-1][0];}

由于dp[i] [0] 只受 dp[i-1] [0] 和 dp[i-1] [1] 的影响,dp[i] [1] 只受 dp[i-1] [1] 的影响,所以可以化为一维数组对代码进行优化

public int maxProfit(int[] prices) {int[] dp = new int[2];dp[0] = 0;dp[1] = -prices[0];for (int i = 1; i < prices.length; i++) {dp[0] = Math.max(dp[0],dp[1] + prices[i]);dp[1] = Math.max(-prices[i],dp[1]);}return dp[0];}

二、买卖股票的最佳时机II (LeetCode 122)

可以完成多次买卖,但是不能同时进行多笔交易,需要卖出后才能再次买入。

与上一题121相比,区别在于dp[i] [1] 受 dp[i-1] [0] 的影响,保证买入前先卖出

public int maxProfit(int[] prices) {int [][]dp = new int[prices.length][2];dp[0][0] = 0;dp[0][1] = -prices[0];for (int i = 1; i < prices.length; i++) {dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);dp[i][1] = Math.max(dp[i-1][0]-prices[i],dp[i-1][1]);}return dp[prices.length-1][0];}

由于dp[i] [0] 只受 dp[i-1] [0] 和 dp[i-1] [1] 的影响,dp[i] [1] 只受 dp[i-1] [1] 的影响,所以可以化为一维数组对代码进行优化

public int maxProfit(int[] prices) {int[] dp = new int[2];dp[0] = 0;dp[1] = -prices[0];for (int i = 1; i < prices.length; i++) {dp[0] = Math.max(dp[0],dp[1] + prices[i]);dp[1] = Math.max(dp[0] - prices[i],dp[1]);}return dp[0];}

三、买卖股票的最佳时机 III(LeetCode 123)

最多可以完成两次买卖,但不能同时进行多笔交易,需要卖出后才能再次买入。

可以看出股票有四个状态:第一次买入buy1,第一次卖出sell1,第二次买入buy2,第二次卖出sell2。

  1. 第一次买入buy1 取决于在第i天时,未操作时买入的价格前面买入的价格,不进行任何操作buy1 = max(-prices[i],buy1)
  2. 第一次卖出sell1 取决于在第i天时,buy1加上卖出时的价格卖出后,不进行任何操作sell1 = max(buy1+prices[i],sell1)
  3. 第二次买入buy2 取决于在第i天时,sell1后减去买入的价格买入后,不进行任何操作buy2 = max(sell1-prices[i],buy2)
  4. 第二次卖出sell2 取决于在第i天时,buy2后加上卖出的价格卖出后,不进行任何操作sell2 = max(buy2+prices[i],sell2)
static int maxProfit(int[] prices) {int buy1 = -prices[0],sell1 = 0;int buy2 = -prices[0],sell2 = 0;for (int i = 0; i < prices.length; i++) {buy1 = Math.max(-prices[i],buy1);sell1 = Math.max(buy1 + prices[i],sell1);buy2 = Math.max(sell1 - prices[i],buy2);sell2 = Math.max(buy2 + prices[i],sell2);}return sell2;}

四、买卖股票的最佳时机 IV(LeetCode 188)

最多可以完成k次买卖,但不能同时进行多笔交易,需要卖出后才能再次买入。

可以用buy[i] [j] 和 sell[i] [j] 这两个二维数组来分别表示买入和卖出的状态,其中i表示第i天,j表示当前是第j次交易。

  1. buy[i] [j] 可以由 在第i-1天持有股票,不做任何操作在第i天买入股票决定(在第i天买入股票的状态是sell[i-1] [j],表示在第i天前股票已经卖出) :buy[i] [j] = max(buy[i-1] [j] , sell[i-1] [j] + prices[i])
  2. sell[i] [j] 可以由 在第i-1天卖出股票,不做任何操作在第i天卖出股票决定 (在第i天卖出股票的状态是buy[i-1] [j-1],表示在第i-1天前买入的股票,此时还是属于第j-1次交易):sell[i] [j] = max(buy[i-1] [j-1] + prices[i] , sell[i-1] [j])

边界问题:

  1. buy[0] [1…k] 和 sell[0] [1…k] 时,由于在第一天只有prices[0] 唯一的股价,不可能有任何交易,所以可以把他们设置成很小的值表示没有交易的状态。
  2. buy[0] [0] 可以表示在第一天买入股票,则可以初始化:buy[0] [0] = -prices[0]
  3. sell[0] [0] 可以表示在第一天不做任何操作,手上不持有股票,则可以舒适化:sell[0] [0] = 0
public int maxProfit(int k, int[] prices) {if (prices.length == 0) return 0;k = Math.min(k,prices.length/2);int[][] buy = new int[prices.length][k+1];int[][] sell = new int[prices.length][k+1];buy[0][0] = -prices[0];sell[0][0] = 0;for (int i = 1; i <= k; i++) {buy[0][i] = sell[0][i] = Integer.MIN_VALUE/2;}for (int i = 1; i < prices.length; i++) {buy[i][0] = Math.max(buy[i-1][0],sell[i-1][0]-prices[i]);for (int j = 1; j <= k; j++) {buy[i][j] = Math.max(buy[i-1][j],sell[i-1][j] - prices[i]);sell[i][j] = Math.max(buy[i-1][j-1] + prices[i],sell[i-1][j]);}}return Arrays.stream(sell[prices.length-1]).max().getAsInt();}

由状态转移方程可以看出buy[i] [j] 和 sell[i] [j] 都从buy[i-1] […],sell[i-1] […]转移而来,所以我们可以用一维数组来进行优化

buy[j] = max( buy[j] , sell[j] - prices[i] )

sell[j] = max( buy[j-1] + prices[i] , sell[j] )

这里可以看到,由于buy[j] 先进行运算,得到的 buy[j] 覆盖了 buy[j] 原来的值,相当于二维数组中buy[i-1] [j-1] 被 buy[i] [j-1] 覆盖了,但结果其实没有影响。

由于 buy[j - 1] -> buy[i] [j-1] =  max( buy[i-1] [j-1] , sell[i-1] [j-1] - prices[i] )代入 sell[j] = max(sell[j] , buy[i-1] [j-1] + prices , sell[i-1] [j-1])

因为sell[i - 1] [j - 1] 表示的是 在同一天内买入和卖出,不会带来额外收益,对答案不产生影响。

public int maxProfit(int k, int[] prices) {if (prices.length == 0) return 0;k = Math.min(k,prices.length/2);int[] buy = new int[k+1];int[] sell = new int[k+1];buy[0] = -prices[0];sell[0] = 0;for (int i = 1; i <= k; i++) {buy[i] = sell[i] = Integer.MIN_VALUE/2;}for (int i = 1; i < prices.length; i++) {buy[0] = Math.max(buy[0],sell[0]-prices[i]);for (int j = 1; j <= k; j++) {buy[j] = Math.max(buy[j],sell[j] - prices[i]);sell[j] = Math.max(buy[j-1] + prices[i],sell[j]);}}return Arrays.stream(sell).max().getAsInt();}

五、最佳买卖股票时机含冷冻期(LeetCode 309)

可以完成多次买卖,但不能同时进行多笔交易,需要卖出后才能再次买入,卖出后有一天的冷冻期,不能买入。

可以定义一个dp[] []二维数组

  1. dp[i] [0]表示: 手上持有股票的最大收益
  2. dp[i] [1]表示: 手上不持有股票,并且处于冷冻期中的累计最大收益
  3. dp[i] [2]表示: 手上不持有股票,并且不在冷冻期中的累计最大收益

由此可以推出状态方程

  • dp[i] [0] 可以由 在第 i-1天持有股票不做任何操作 和 在第i天购买股票,且不处于冷冻期 决定:dp[i] [0] = max(dp[i-1] [0],dp[i-1] [2])
  • dp[i] [1] 可以由 在第 i-1天卖出股票 决定:dp[i] [1] = dp[i-1] [0] + prices[i]
  • dp[i] [2] 可以由 在 第 i-1天不持有股票,且处于冷冻期在第 i-1天不持有股票,且不处于冷冻期 决定:dp[i] [2] = max(dp[i-1] [1],dp[i-1] [2])

边界条件:dp[0] [0] = -prices[0] 表示在 第一天买入。dp[0] [1] 和 dp[0] [2] 表示在第一天不持有股票,则默认为0。

public int maxProfit(int[] prices) {if (prices.length == 0) return 0;int[][] dp = new int[prices.length][3];dp[0][0] = -prices[0];for (int i = 1; i < prices.length; i++) {// dp[i][0]: 手上持有股票的最大收益// dp[i][1]: 手上不持有股票,并且处于冷冻期中的累计最大收益// dp[i][2]: 手上不持有股票,并且不在冷冻期中的累计最大收益dp[i][0] = Math.max(dp[i-1][0],dp[i-1][2] - prices[i]);dp[i][1] = dp[i-1][0] + prices[i];dp[i][2] = Math.max(dp[i-1][1],dp[i-1][2]);}return Math.max(dp[prices.length-1][1],dp[prices.length-1][2]);}

由上可以看出 dp[i] […] 都由 dp[i-1] […] 推导出来,所以可以设置三个变量对代码进行优化

static int maxProfit(int[] prices) {if (prices.length == 0) return 0;//dp0 表示第i-1天,手上持有股票的最大收益//dp1 表示第i-1天,手上不持有股票,处于冷冻期的累计最大收益//dp2 表示第i-1天,手上不持有股票,不处于冷冻期的累计最大收益int dp0 = -prices[0];int dp1 = 0, dp2 = 0;for (int i = 1; i < prices.length; i++) {int newdp0 = Math.max(dp0,dp2-prices[i]);int newdp1 = dp0 + prices[i];int newdp2 = Math.max(dp1,dp2);dp0 = newdp0;dp1 = newdp1;dp2 = newdp2;}return Math.max(dp1,dp2);}

六、买卖股票的最佳时机含手续费(LeetCode 714)

可以完成多次买卖,但是不能同时进行多笔交易,需要卖出后才能再次买入,卖出时需要手续费。

与 买卖股票的最佳时机II 很相似,只是多了手续费的条件

定义一个dp[] [] 二维数组,dp [i] [0]表示没有股票的状态,dp [i] [1]表示持有股票的状态

static int maxProfit(int[] prices,int fee) {int[][] dp = new int[prices.length][2];dp[0][0] = 0;dp[0][1] = -prices[0];for (int i = 1; i < prices.length; i++) {dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i] - fee);dp[i][1] = Math.max(dp[i-1][0] - prices[i],dp[i-1][1]);}return dp[prices.length-1][0];}

由于dp[i] [0] 和 dp[i] [1] 只受 dp[i-1] [0] 和 dp[i-1] [1] 的影响,所以可以设置常量对代码进行优化

    static int maxProfit(int[] prices,int fee) {int buy = -prices[0],sell = 0;for (int i = 1; i < prices.length; i++) {buy = Math.max(buy,sell - prices[i]);sell = Math.max(buy + prices[i] - fee,sell);}return sell;}

LeetCode买卖股票问题集合(六种股票问题)相关推荐

  1. leetcode买卖股票问题(思路、方法、code)

    一文解决Leetcode买卖股票问题 对于前3个问题,均采用了比较巧妙的解法.由于第4个问题具有非常强的泛型,因此采用了DP,第4个问题的dp如果理解的话,实际上只需要稍加修改状态便可以用该dp思路应 ...

  2. LeetCode买卖股票之一:基本套路(122)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<LeetCode买卖股票>系列 在L ...

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

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

  4. leetcode 买卖股票问题

    leetcode 买卖股票问题 lc121 买卖股票最佳时机 lc122 买卖股票最佳时机II lc123. 买卖股票的最佳时机 III lc188. 买卖股票的最佳时机 IV lc121 买卖股票最 ...

  5. [Leetcode] 买卖股票合集(动态规划)

    写完这套题,再搞一台时光机,财务自由不是梦(Doge) ================================== 相关题目链接 121 买卖股票的最佳时机 122 买卖股票的最佳时机 II ...

  6. 【leetcode买卖股票系列问题】多次买卖/手续费/冻结期

    一.目录 一.目录 二.股票系列问题 1.买卖股票的最佳时机(121题) 1.1.题目 1.2.思路 1.3.代码实现(1种) 2.买卖股票的最佳时机II(122题) 2.1.题目 2.2.思路 2. ...

  7. leetcode买卖股票最佳时机相关问题分析

    买卖股票最佳时机相关问题分析 前言 1.121买卖股票的最佳时机 思路分析 代码及运行结果 2.122买卖股票的最佳时机II 思路分析 代码及运行结果 3.123买卖股票的最佳时机III 思路分析 代 ...

  8. 【LeetCode】剑指 Offer 63. 股票的最大利润

    [LeetCode]剑指 Offer 63. 股票的最大利润 文章目录 [LeetCode]剑指 Offer 63. 股票的最大利润 package offer;public class Soluti ...

  9. R语言使用quantmod包的getSymbols函数从指定金融数据源获取指定时间段的股票数据、对股票进行除权除息调整

    R语言使用quantmod包的getSymbols函数从指定金融数据源获取指定时间段的股票数据.对股票进行除权除息调整 目录 R语言使用quantmod包的getSymbols函数从指定金融数据源获取 ...

  10. R语言使用quantmod包的getSymbols函数从指定金融数据源获取指定时间段的股票数据、对股票进行除权除息调整、设置使用Adjusted列的数据

    R语言使用quantmod包的getSymbols函数从指定金融数据源获取指定时间段的股票数据.对股票进行除权除息调整.设置使用Adjusted列的数据 目录 R语言使用quantmod包的getSy ...

最新文章

  1. 用 Linux 的 watch 命令观察命令和任务
  2. 【有美女看】提升用户体验,你不得不知道的事儿——巧用全屏与沉浸式体验,让用户更舒心~...
  3. Android Https相关完全解析 当OkHttp遇到Https
  4. 深入理解java SPI机制
  5. 撸一个简易聊天室,不信你学不会实时消息推送(附源码)
  6. 老年手机英文改中文_不服来战:“老年人才用9键!”
  7. macOS下利用dSYM文件将crash文件中的内存地址转换为可读符号
  8. springMVC结合jersey实现跨服务器文件上传
  9. 国内语料库建设一览表
  10. CSS从入门到精通——文本与字体样式
  11. 基于微信小程序的外卖点餐系统
  12. 2345等浏览器主页劫持的解决办法
  13. IT 常用词汇(一)
  14. 群晖服务器白群晖有哪些型号,白群晖和黑群晖,有什么区别?
  15. 华为鸿蒙操作系统国美通讯,国美通讯(600898)03月14日14:30大单揭秘
  16. Linux内核浮点运算
  17. bzoj 3772: 精神污染 (主席树+dfs序)
  18. 关于PPP拨号的接入点
  19. 微信指数批量采集、导出
  20. 求任意整数模3的余数

热门文章

  1. 大数据产品经理极速撰写PRD的5个步骤
  2. 网络管理员配置linux,Linux操作系统中,网络管理员可以通过修改()文件对Web服务器端口进行配置。...
  3. 使用小鼠数据进行GSEA分析
  4. GAN 对抗生成网络代码实现
  5. 可作为工质状态参数的是_热力学
  6. Windows Defender Antivirus Service关闭方法
  7. 华为云桌面云中心调试步骤_轻松进行云维护的5个步骤
  8. FFmpeg简述,源码分析,录制/压缩/水印/剪切/旋转/滤镜/美颜/上传视频等(CPU软编码和解码)
  9. 污水处理系统 | 污水处理项目程序规范,图纸清晰
  10. 动手制作属于你自己的WIN PE3.0