【动态规划】简单多状态dp问题(2)买卖股票问题

这篇具有很好参考价值的文章主要介绍了【动态规划】简单多状态dp问题(2)买卖股票问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

买卖股票问题

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

【动态规划】简单多状态dp问题(2)买卖股票问题

1. 最佳买卖股票时机含冷冻期(买卖股票Ⅰ)

传送门:力扣309. 最佳买卖股票时机含冷冻期

题目:

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

1.1 题目解析

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

越难的dp问题,看示例只能起到了解题目的效果,一般推不出啥普遍的规律,所以接下来就是我们的算法原理,通过动归的思想去理解,才会豁然开朗!

1.2 算法原理

1.2.1 状态表示

我们需要通过经验 + 题目要求去决定状态表示:

  1. 根据题目的意境以及数据结构,我们得出需要建立一维的dp表(大小为 n)
    • 对于为什么用一维,首先这道题数据结构为一维的,而一维如果确实可以解决问题就没有必要上升到二维
  2. 经验:以某个坐标为结尾或者以某个坐标为起点去研究题目问题!
    • 此题用的是“结尾”

再根据经验,一般dp表的其中一值就应该是答案!

  • 所以含义应该就是“最大收益”

综合得到状态表示:dp[i]表示就是从起点到i坐标这些天 结束后 的最大收益

  • 应该为结束后,否则会不全面,即第i + 1天干了什么跟dp[i]的值无关,那么最后一天干了什么将没有意义,这是不应该出现的!

而这道题,与之前做过的题不一样的是,一个坐标的状态有三种情况,需要我们继续细化

  1. 持有股票(可交易)
  2. 未持有股票(可交易)
  3. 冷冻期

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

所以,最终的状态表示为:

f[i]表示的是,从起点到 i 坐标的这些天结束后,为可交易的持有股票状态的情况下的最大收益

g[i]表示的是,从起点到 i 坐标的这些天结束后,为可交易的未持有股票状态的情况下的最大收益

h[i]表示的是,从起点到 i 坐标的这些天结束后,为不可交易的冷冻期状态的情况下的最大收益

1.2.2 状态机

在推导状态转移方程之前,我们要做一些准备工作

  • 因为这道题更我们之前做的题不一样,因为从一天到另一天,状态的转换具有一定的逻辑关系,稍微有点复杂并不是“齐次对称的”,而我们需要考虑到各个情况,所以就可以这样做:

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

  • 所以,最终得出有五种转换关系的存在
    1. 到 f 的有两种
    2. 到 g 的有两种
    3. 到 h 的有一种

而这一幅图,就是”状态机”

1.2.3 状态转移方程

同样的套路,我们需要根据已确定的dp表的值来推导 f[i] 、 g[i] 以及 h[i]的值,并且牢记他们的状态表示!

  1. 我们以坐标 i 为结尾
  2. 根据“最近一步”去划分问题

“最近一步”可以理解为“必然事件”

  • 此题的“必然事件”就是,到达坐标 i 之前,必然要先到达坐标 i - 1

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

结合状态机:
【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

  1. 如果这一天结束后为f,那么前一天结束后可能是g或者f

    • 如果前一天是g,则今天的收益应该为g[i - 1] - prices[i](前一天的收益减去上花掉的钱)
      • 因为g[i - 1]代表第i天结束后为g,则收费应该算的是第i + 1天的费用,即prices[i]
      • 而因此,第i + 1天结束后为f
    • 如果前一天是f,则今天的收益不变,为f[i - 1]
    • 取较大值
  2. 如果这一天结束后为g,那么前一天结束后可能为g或者h

    • 如果前一天是g,则今天的收益不变,为g[i - 1]
    • 如果前一天是h,则今天的收益不变,为h[i - 1]
    • 取较大值
  3. 如果这一天结束后为h,那么前一天结束后一定为f

    • 今天的收益为f[i - 1] + prices[i] (前一天的收益加上卖掉的钱)
      • 因为f[i - 1]代表第i天结束后为f,则收入应该算的是第i + 1天的费用,即prices[i]
      • 而因此,第i + 1天结束后为h

所以得出状态转移方程:

f[i] = max{g[i - 1] - prices[i], f[i - 1]};

g[i] = max{g[i - 1], h[i - 1]};

h[i] = f[i - 1] + prices[i]

1.2.4 初始化

在第一天结束后

  1. 处于f状态,需要买一张票:f[0] = - prices[0]
  2. 处于可交易的g状态,啥也不干:g[0] = 0
  3. 买一张票立即卖了:h[0] = 0
1.2.5 填表顺序

从做到有,三个表一起填

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

1.2.6 返回值

最后其实处于三种状态都有可能,取较大值即可!

1.3 编写代码

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[] f = new int[n];
        int[] g = new int[n];
        int[] h = new int[n];
        f[0] = -prices[0];
        for(int i = 1; i < n; i++) {
            f[i] = Math.max(f[i - 1], g[i - 1] - prices[i]);
            g[i] = Math.max(g[i - 1], h[i - 1]);
            h[i] = f[i - 1] + prices[i];
        }
        return Math.max(
            Math.max(f[n - 1], g[n - 1]), h[n - 1]
        );
    }
}

时空复杂度都为:O(N)

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

2. 买卖股票的最佳时机含手续费(买卖股票Ⅱ)

传送门:力扣714. 买卖股票的最佳时机含手续费

题目:

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

2.1 题目解析

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

越难的dp问题,看示例只能起到了解题目的效果,一般推不出啥普遍的规律,所以接下来就是我们的算法原理,通过动归的思想去理解,才会豁然开朗!

2.2 算法原理

2.2.1 状态表示

我们需要通过经验 + 题目要求去决定状态表示:

  1. 根据题目的意境以及数据结构,我们得出需要建立一维的dp表(大小为 n)
    • 对于为什么用一维,首先这道题数据结构为一维的,而一维如果确实可以解决问题就没有必要上升到二维
  2. 经验:以某个坐标为结尾或者以某个坐标为起点去研究题目问题!
    • 此题用的是“结尾”

再根据经验,一般dp表的其中一值就应该是答案!

  • 所以含义应该就是“最长预约时长”

综合得到状态表示:dp[i]表示就是起点到坐标为 i 的位置【这些天结束后】的最大收益

而这道题,与之前做过的题不一样的是,一个坐标的状态有两种情况,需要我们继续细化

  1. 持票
  2. 未持票

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

所以,最终的状态表示为:

f[i]表示的是,从起点到 i 坐标的这些天结束后,持票的情况下的最大收益

g[i]表示的是,从起点到 i 坐标的这些天结束后,未持票的情况下的最大收益

2.2.3 状态机

同样的画一下状态机:
【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

2.2.3 状态转移方程

同样的套路,我们需要根据已确定的dp表的值来推导 f[i] 和 g[i] 的值,并且牢记他们的状态表示!

  1. 我们以坐标 i 为结尾
  2. 根据“最近一步”去划分问题

“最近一步”可以理解为“必然事件”

  • 此题的“必然事件”就是,到达坐标 i 之前,必然要先到达坐标 i - 1
    【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法
  1. 这一天结束后为持票的话,前一天结束后可能为f或者g
    • f的话,收益不变,为f[i - 1]
    • g的话,支付票价,为g[i - 1] - prices[i]
  2. 这一天结束后为未持票的话,前一天结束后可能为f或者g
    • f的话,支付手续费获得收入,为f[i - 1] + prices[i] - fee
    • g的话,收益不变,为g[i - 1]

而1代表着f表怎么填,2代表着g表怎么填

所以得出状态转移方程:

f[i] = max{f[i - 1], g[i - 1] - prices[i]};

g[i] = max{f[i - 1] + prices[i] - fee, g[i - 1]};

2.2.4 初始化

在第一天结束后

  1. 为持票状态,即买一张票,为prices[0] * (-1)
  2. 为未持票状态,啥也不干,为0
2.2.5 填表顺序

从左往右两个表一起填
【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

2.2.6 返回值

最后一天结束后,两种情况收益的较大值

2.3 编写代码

class Solution {
    public int maxProfit(int[] prices, int fee) {
        int n = prices.length;
        int[] f = new int[n];
        int[] g = new int[n];
        f[0] = -prices[0];
        for(int i = 1; i < n; i++) {
            f[i] = Math.max(f[i - 1], g[i - 1] - prices[i]);
            g[i] = Math.max(g[i - 1], f[i - 1] + prices[i] - fee);
        }
        return Math.max(f[n - 1], g[n - 1]);
    }
}

时空复杂度都为:O(N)

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

3. 买卖股票的最佳时期限制次数(买卖股票Ⅲ)

传送门:力扣123.买卖股票的最佳时机 III

题目:

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

3.1 题目解析

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

越难的dp问题,看示例只能起到了解题目的效果,一般推不出啥普遍的规律,所以接下来就是我们的算法原理,通过动归的思想去理解,才会豁然开朗!

3.2 算法原理

3.2.1 状态表示

我们需要通过经验 + 题目要求去决定状态表示:

  1. 根据题目的意境以及数据结构,我们得出需要建立二维的dp表(大小为 n × 3)
  2. 经验:以某个坐标为结尾或者以某个坐标为起点去研究题目问题!
    • 此题用的是“结尾”

再根据经验,一般dp表的其中一值就应该是答案!

  • 所以含义应该就是“最大收益”

综合得到状态表示:dp[i][j]表示就是起点到坐标为 i 的位置这些天结束后交易次数为j的最大收益

而这道题,与之前做过的题不一样的是,一个坐标的状态有两种情况,需要我们继续细化

  1. 持票
  2. 未持票

在之前的题目里,我们到达一个坐标并无其他选择,而现在有~
【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

所以,最终的状态表示为:

f[i] [j]表示的是,从起点到 i 坐标的这些天结束后,持票且交易次数为 j 的情况下的最大收益

g[i] [j]表示的是,从起点到 i 坐标的这些天结束,未持票且交易次数为 j 的情况下的最大收益

3.2.2 状态机

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

3.2.3 状态转移方程

同样的套路,我们需要根据已确定的dp表的值来推导 f[i] [j] 和 g[i] [j]的值,并且牢记他们的状态表示!

  1. 我们以坐标 i 为结尾
  2. 根据“最近一步”去划分问题

“最近一步”可以理解为“必然事件”

  • 此题的“必然事件”就是走到(i, j)之前,
    1. f表,先要走到(i - 1, j)
    2. g表,先要走到(i - 1, j - 1)或者(i - 1, j)
      • 完成第j次交易之前,要先完成第j-1次交易

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

  1. 这一天结束后为持票的话,前一天结束后可能为f或者g
    • f的话,收益不变,为f[i - 1] [j]
    • g的话,支付票价,为g[i - 1] [j] - prices[i]
  2. 这一天结束后为未持票的话,前一天结束后可能为f或者g
    • f的话,支付手续费获得收入,为f[i - 1] [j - 1] + prices[i]
    • g的话,收益不变,为g[i - 1] [j]

而1代表着f表怎么填,2代表着g表怎么填

所以得出状态转移方程:

f[i] [j] = max{f[i - 1] [j], g[i - 1] [j] - prices[i]};

g[i] [j] = max{g[i - 1] [j], f[i - 1] [j - 1] + prices[i]};

问题:怎么做到限制次数的?

首先,到达交易三次的前提是到达交易两次

  • 那么,交易两次后,其值并没有追加在其他元素上,那么就不会增加交易次数

依此限制了交易次数

3.2.4 初始化

初始化:

f表:

  • 第0行:f[0] [0] = - prices[0] 、f[0] [1] = -∞、f[0] [2] = -∞(取-∞这是因为不存在这种可能)
    • -∞取MIN_VALUE的话,由于上面设计一个减操作,所以它反而变成了一个很大的正数,而我们想要的是让其绝对不会被选中,所以应该让 -∞ = -0x3f3f3f3f(常用的无穷大数)

g表:

  • 第0行:g[0] [0] = 0 、g[0] [1] = -∞、g[0] [2] = -∞(取-∞这是因为不存在这种可能)
  • 第0列:都为0(其实g[i] [0] = g[i - 1] [0],可以在状态转移方程中去处理)

即,g表的状态转移方程为:

  1. g[i] [j] = g[i - 1] [j]
  2. 如果j >= 1,g[i] [j] = max{g[i] [j], f[i - 1] [j - 1]};
3.2.5 填表顺序

从上到下两个表一起填每一行,每一行每一列一起填

3.2.6 返回值

最后一天结束后,f或者g状态下,各个交易次数都要算上,去最大值!

3.3 编写代码

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[][] f = new int[n][3];
        int[][] g = new int[n][3];

        f[0][0] = -prices[0];
        for(int i = 1; i < 3; i++) {
            f[0][i] = -0x3f3f3f3f;
            g[0][i] = -0x3f3f3f3f;
        }
        for(int i = 1; i < n; i++) {
            for(int j = 0; j < 3; j++) {
                f[i][j] = Math.max(f[i - 1][j], g[i - 1][j] - prices[i]);
                g[i][j] = g[i - 1][j];
                if(j >= 1) {
                    g[i][j] = Math.max(g[i][j], f[i - 1][j - 1] + prices[i]);
                }
            }
        }
        int min = -0x3f3f3f3f;
        for(int i = 0; i < 3; i++) {
            min = Math.max(min, f[n - 1][i]);
            min = Math.max(min, g[n - 1][i]);
        }
        return min;
    }
}

时空复杂度都为:O(N)

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

4. 买卖股票的最佳实际限制次数(买卖股票Ⅳ)

传送门:力扣188. 买卖股票的最佳时机 IV

题目:

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

4.1 与第三题的关系

这道题,跟第三题唯一的区别就是,第三题限制为2次,而这道题限制为k次

  • 而2次只不过是k次中的其中一种情况罢了,而他们的解法,一模一样!

第三题的dp表是n × 3,填表时因为空间的限制,无法达到3次及以上

那么这道题,dp表设为n × (k + 1),填表由于空间限制,也无法达到k次以上
【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

  • 由于影响值的只有左上或者上侧,所以右侧的列的存在并不会影响左侧的值
  • 也就是说,如果这个很大的表是通用的,使用其的一部分,就能解决个别的问题

4.2 编写代码

class Solution {
    public int maxProfit(int k, int[] prices) {
        int n = prices.length;
        int[][] f = new int[n][k + 1];
        int[][] g = new int[n][k + 1];

        f[0][0] = -prices[0];
        for(int i = 1; i < k + 1; i++) {
            f[0][i] = -0x3f3f3f3f;
            g[0][i] = -0x3f3f3f3f;
        }
        for(int i = 1; i < n; i++) {
            for(int j = 0; j < k + 1; j++) {
                f[i][j] = Math.max(f[i - 1][j], g[i - 1][j] - prices[i]);
                g[i][j] = g[i - 1][j];
                if(j >= 1) {
                    g[i][j] = Math.max(g[i][j], f[i - 1][j - 1] + prices[i]);
                }
            }
        }
        int min = -0x3f3f3f3f;
        for(int i = 0; i < k + 1; i++) {
            min = Math.max(min, f[n - 1][i]);
            min = Math.max(min, g[n - 1][i]);
        }
        return min;
    }
}

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法

时空复杂度都为:O(N * k)

【动态规划】简单多状态dp问题(2)买卖股票问题,剑指offer与算法,动态规划,算法


文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭🦆

本文代码链接:动态规划04/src/Main.java · 游离态/马拉圈2023年6月 - 码云 - 开源中国 (gitee.com)文章来源地址https://www.toymoban.com/news/detail-519245.html


到了这里,关于【动态规划】简单多状态dp问题(2)买卖股票问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【算法】力扣【动态规划、状态机】309. 买卖股票的最佳时机含冷冻期

    309. 买卖股票的最佳时机含冷冻期 本文介绍解决力扣平台上第309号问题——“买卖股票的最佳时机含冷冻期”的算法。这是一个中等难度的问题,其核心是通过设计一个算法来计算在给定的股票价格数组 prices 下,能够获取的最大利润。股票价格数组 prices 中的每个元素 pric

    2024年01月18日
    浏览(37)
  • 算法沉淀 —— 动态规划篇(简单多状态dp问题上)

    几乎所有的动态规划问题大致可分为以下5个步骤,后续所有问题分析都将基于此 1.、状态表示:通常状态表示分为以下两种,其中更是第一种为主。 以i为结尾 ,dp[i] 表示什么,通常为代求问题(具体依题目而定) 以i为开始 ,dp[i]表示什么,通常为代求问题(具体依题目而

    2024年04月11日
    浏览(32)
  • 【算法优选】 动态规划之简单多状态dp问题——贰

    动态规划相关题目都可以参考以下五个步骤进行解答: 状态表示 状态转移⽅程 初始化 填表顺序 返回值 后面题的解答思路也将按照这五个步骤进行讲解。 给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 设计一个算法计算出最大利润。在满足以下约束条件下,

    2024年04月12日
    浏览(27)
  • 算法沉淀 —— 动态规划篇(简单多状态dp问题下)

    几乎所有的动态规划问题大致可分为以下5个步骤,后续所有问题分析都将基于此 1.、状态表示:通常状态表示分为基本分为以下两种,其中更是以第一种为甚。 以i为结尾 ,dp[i] 表示什么,通常为代求问题(具体依题目而定) 以i为开始 ,dp[i]表示什么,通常为代求问题(具

    2024年04月16日
    浏览(36)
  • 【动态规划】简单多状态dp问题(1)打家劫舍问题

    打家劫舍问题 传送门:面试题 17.16. 按摩师 题目: 1.1 题目解析 越难的dp问题,看示例只能起到了解题目的效果,一般推不出啥普遍的规律,所以接下来就是我们的算法原理,通过动归的思想去理解,才会豁然开朗! 1.2 算法原理 1.2.1 状态表示 我们需要通过经验 + 题目要求去

    2024年02月12日
    浏览(34)
  • 【LeetCode动态规划#13】买卖股票含冷冻期(状态众多,比较繁琐)、含手续费

    力扣题目链接(opens new window) 给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。 设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票): 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)

    2023年04月25日
    浏览(33)
  • 动态规划(day11)买卖股票问题进阶

    目录 123.买卖股票的最佳时机III 看到题目的第一想法                看到代码随想录之后的想法 自己实现过程中遇到的困难 188.买卖股票的最佳时机IV 看到题目的第一想法                看到代码随想录之后的想法 自己实现过程中遇到的困难 力扣题目链接(opens new windo

    2024年01月21日
    浏览(45)
  • day49-动态规划10-买卖股票问题

    但是利用其他思路只能解决具体场景下的问题,并不能解决通用的一些问题。 dp[i][0] :表示第i天持有该股票的最大收益, dp[i][1] 表示第i天不持有该股票的最大收益。需要注意的是第i天的情况是什么样,并不是表示第i天就卖出了这只股票,而是表示 递推公式: dp[i][0] 第一

    2024年02月08日
    浏览(31)
  • 【动态规划】12简单多状态dp问题_打家劫舍II_C++ (medium)

    题目链接:leetcode打家劫舍II 目录 题目解析: 算法原理 1.状态表示 2.状态转移方程 3.初始化 4.填表顺序 5.返回值 编写代码 题目让我们求 在不触动警报装置的情况下  ,能够偷窃到的最高金额。 由题可得: 第一个房屋和最后一个房屋是紧挨着的 如果两间相邻的房屋在同一晚

    2024年02月02日
    浏览(37)
  • [Leetcode] 买卖股票合集(动态规划)

    写完这套题,再搞一台时光机,财务自由不是梦(Doge) ================================== 相关题目链接 121 买卖股票的最佳时机 122 买卖股票的最佳时机 II 123 买卖股票的最佳时机 III 188 买卖股票的最佳时机 IV 309 买卖股票的最佳时机含冷冻期 714 买卖股票的最佳时机含手续费 给定一

    2023年04月16日
    浏览(30)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包