当前位置: 首页 > article >正文

【动态规划】【简单多状态dp问题】买卖股票相关问题(冷冻期、手续费、限制次数)

5. 买卖股票的最佳时机含冷冻期

309. 最佳买卖股票时机含冷冻期
image.png|495

算法原理

  1. 确定状态表示
    • dp[i]:表示第 i 天的最大利润
  • 细分
    • i 天结束的时候是“买入”状态(0)
    • i 天结束的时候是“可交易”状态(1)
    • i 天结束的时候是“冷冻期”状态(2)

  1. 状态转移方程

分析状态的时候,就一个状态一个状态的看(一共 3 x 3=9 种)image.png|387

  • 买入
    • “买入“==>“买入”;在 i-1 天的时候什么也不干,到了第 i 天之后已然是“买入状态”

    • “可交易”==>“买入”:在第 i 天进行股票买入,-price[i]

    • “冷冻期”x=>“买入”:这一天无法交易,故不能买入股票,所以无法实现

    • dp[i][0] = max(dp[i-1][0], dp[i-1][1] - price[i])


  • 可交易
    • “可交易”==>“可交易”:i-1 天不买,则到了 i 天也是“可交易”

    • “冷冻期”==>“可交易”:i-1 天是冷冻期,则第 i 天就是可交易的了

    • “买入”x=>可交易:必须得经过冷冻期

    • dp[i][1] = max(dp[i-1][1], dp[i-1][2])


  • 冷冻期
    • “冷冻期”x=>“冷冻期”:不能连续两天都是“冷冻期”

    • “买入”==>“冷冻期”:在第 i 天将股票给卖了,就变成“冷冻期”了,+price[]

    • “可交易”x=>“冷冻期”:到不了手里没股票,没卖的

    • dp[i][2] = dp[i-1][0] + price[i]


  1. 初始化

    • 都出现了 i-1,所以要初始化第一个位置
    • dp[0][0] = -price[0]
    • dp[0][1] = 0
    • dp[0][2] = 0
  2. 填表顺序

    • 从左往右
    • 一次填写三个表
  3. 返回值

    • 返回 max(dp[n-1][1], dp[n-1][2])
    • 第一个表肯定不是最终答案,手里的股票都还没卖,肯定比卖出去的低

代码编写

public int maxProfit(int[] prices) {  
    int n = prices.length;  
    int[][] dp = new int[n][3];  
  
    //2. 初始化  
    dp[0][0] = -prices[0];  
  
    //3. 填表  
    for (int i = 1; i < n; i++) {  
        dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i]);  
        dp[i][1] = Math.max(dp[i-1][1], dp[i-1][2]);  
        dp[i][2] = dp[i-1][0] + prices[i];  
    }  
    return Math.max(dp[n-1][1], dp[n-1][2]);  
}

6. 买卖股票的最佳时期含手续费

714. 买卖股票的最佳时期含手续费
image.png|545

算法原理

  1. 确定状态表示

    • dp[i] 表示:第 i 天结束之后,所能获得的最大利润
      • f[i]:处于“买入”,有股票,此时的最大利润
      • g[i]:处于“卖出”,可交易,此时的最大利润 `
  2. 状态转移方程

    • f[i] = max(f[i-1], g[i-1] - price[i])
    • g[i] = max(g[i-1], f[i-1] + price[i] - fee)
  3. 初始化

    • 第 0 天的时候处于买入状态,那就只能把那天的股票买了 f[0] = -price[0]
    • 第 0 天的时候处于卖出的状态,那就啥也不干 g[0] = 0
  4. 填表顺序

    • 从左往右
    • 两表一起填
  5. 返回值

    • 只有处于卖出状态才可能是最大利润
    • 直接返回 g[n-1]

代码编写

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 g[n-1];  
}

7. 买卖股票的最佳时机 III

123. 买卖股票的最佳时机 III
image.png|426

算法原理

  1. 确定状态表示
    • dp[i] 表示:第 i 天结束之后,所能获得的最大利润

一维表示第 i 天;二维表示交易次数(可加一维表示买入还是卖出,不过我们可以直接用两个表)

  • f[i][j]:第 i 天结束后,完成了 j 次交易,此时处于“买入“状态下的最大利润
  • g[i][j]:第 i 天结束后,完成了 j 次交易,此时处于“卖出”状态下的最大利润

  1. 状态转移方程image.png|423
    • f[i][j] = max(f[i-1][j], g[i-1][j]-prices[i-1])
    • g[i][j] = max(g[i-1][j], f[i-1][j-1] + prices[i]),今天的交易次数是 j,要找到昨天的,就得 j-1
      1. g[i][j] = g[i-1][j]。因为第一次的时候,j-1<0,不符合要求
      2. if(j-1>=0) g[i][j] = max(g[i][j], f[i-1][j-1]+prices[i])

此处分析没有定义 j 的大小(交易次数),

  1. 初始化

image.png

  • 只需要初始化第一行。横坐标表示第 0 天结束之后,纵坐标表示完成交易笔数
  • 选最小值的时候,不能选 INT_MIN,因为上面还有-1 的操作,会导致越界。所以我们取 -0x3f3f3f3f,这是最小值的一半
  1. 填表顺序

    • 从上往下填写每一行
    • 每一行从左往右
    • 两表一起填
  2. 返回值

    • g 表的最后一行里面的最大值
    • 不考虑 f 表,因为 f 表手里的股票都还没卖出去,肯定不会是最大利润

代码编写

public int maxProfit(int[] prices) {  
    int n = prices.length;  
    int[][] f = new int[n][3];  
    int[][] g = new int[n][3];  
  
    for (int i = 1; i < 3; i++) {  
        f[0][i] = -0x3f3f3f3f;  
        g[0][i] = -0x3f3f3f3f;  
    }  
    f[0][0] = -prices[0];  
  
  
    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 >= 0) g[i][j] = Math.max(g[i][j], 
            f[i-1][j-1]+prices[i]);  
        }  
    }  
    int ret = 0;  
    for (int i = 0; i < 3; i++) {  
        ret = Math.max(ret, g[n-1][i]);  
    }  
    return ret;  
}

8. 买卖股票的最佳时机 Ⅳ

188. 买卖股票的最佳时机 Ⅳ
image.png

算法原理

和上一题一样,只是把 2 变成了 k

代码编写

public int maxProfit(int k, int[] prices) {  
    int n = prices.length;  
    int MIN = -0x3f3f3f3f;  
    int[][] f = new int[n][k+1];  
    int[][] g = new int[n][k+1];  
  
    for (int i = 0; i <= k; i++) {  
        f[0][i] = MIN;  
        g[0][i] = MIN;  
    }  
    f[0][0] = -prices[0];  
    g[0][0] = 0;  
  
    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 >= 0)  g[i][j] = Math.max(g[i-1][j], 
            f[i-1][j-1]+prices[i]);  
        }  
    }  
    int ret = 0;  
    for (int i = 0; i < k+1; i++) {  
        ret = Math.max(ret, g[n-1][i]);  
    }  
    return ret;  
}

http://www.kler.cn/news/366180.html

相关文章:

  • MATLAB基础应用精讲-【数模应用】本量利分析(Cost-Volume-Profit Analysis)
  • 【Python爬虫系列】_031.Scrapy_模拟登陆中间件
  • 大数据-190 Elasticsearch - ELK 日志分析实战 - 配置启动 Filebeat Logstash
  • 证件照电子版怎么弄?不花钱制作方法快来学
  • DSPy:不需要手写prompt啦,You Only Code Once!
  • Mybatis mapper文件 resultType和resultMap的区别
  • MATLAB基础应用精讲-【数模应用】本量利分析(Cost-Volume-Profit Analysis)
  • 【论文阅读】ESRGAN+
  • 项目管理软件中这6个小技巧帮助项目经理同时管理多个项目
  • 水轮发电机油压自动化控制系统解决方案介绍
  • LDR6020:为VR串流线方案注入高效能与稳定性
  • 多台NFS客户端访问一台nfs服务器
  • vitepress一键push和发布到github部署网站脚本
  • spring整合使用xml方式整合Druid数据源连接池
  • 邮件系统SSL加密传输,保护你的电子邮件免受网络威胁
  • 基于SSM考研助手系统的设计
  • 小白对时序数据库的理解
  • 视频美颜平台是如何搭建的?基于直播美颜SDK源码的开发技术详解
  • 推荐一款三维数值建模软件:3DEC
  • C++ —— 《模板进阶详解》,typename和class的用法,非类型模板参数,模板的特化,模板的分离编译
  • 解决Github下载速度慢的问题
  • 青少年编程能力等级测评CPA C++五级试卷(2)
  • 数据结构 ——— C语言实现链式队列
  • 干丹岩教授
  • 公司怎么能帮员工统一管理朋友圈
  • Java 泛型 Lambda 表达式