我爱学算法之——动态规划(四)

一、买卖股票的最佳时机含冷冻期

题目解析

给定一个整数数组 prices,其中prices[i]表示第 i 天的股票价格;计算 最大收益

约束条件

  • 不能同时参与多笔交易(已有股票就不能再买入了)
  • 卖出股票后,有一天的冷静期

算法思路

状态表示

对于这道题,第 i 天结束 存在三种状态:持有股票(买入)不持有股票,处于冷冻期(冷冻)不持有股票,不处于冷冻期(可交易)

所以,这里就需要表示三种状态下的最大收益:

  • dp[i][0] : 第 i 天结束处于 买入 状态,此时的最大收益
  • dp[i][1] : 第 i 天结束处于 冷冻 状态,此时的最大收益
  • dp[i][2] : 第 i 天结束处于 可交易 状态,此时的最大收益

状态转移方程

这里只靠想象,去找这个状态转移还是比较费劲的,可以自己画一个图,思考状态之间是如何转化的:

如上图,状态转移清晰可见,状态转移方程:

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

初始化

这里初始化dp[0][0]dp[0][1]dp[0][2],第一结束处于买入、冷冻、可交易状态的最大收益即可。

返回值

题目要求的是:最大利润,最后一天(n-1)再持有股票(买入状态)没有意义;所以,最终结果应该是 dp[n-1][1]dp[n-1][2]中的最大值。

代码实现

cpp 复制代码
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(3, 0));
        dp[0][0] = -prices[0];
        for (int i = 1; i < n; i++) {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][2] - prices[i]);
            dp[i][1] = dp[i - 1][0] + prices[i];
            dp[i][2] = max(dp[i - 1][2], dp[i - 1][1]);
        }
        return max(dp[n - 1][1], dp[n - 1][2]);
    }
};

二、买卖股票的最佳时机含手续费

题目解析

给定一个数组 proces和一个整数feeproces[i]表示第 i 天的股票价格;fee表示交易股票的手续费用(每笔交易只需支付一次)

约束条件

  • 不能同时参与多笔交易(已有股票就不能再买入了)
  • 每笔交易需要支付手续费用

算法思路

状态表示

这道题目,第 i 天结束,只有两种状态:持有股票、不持有股票

  • dp[i][0] : 表示第 i 天结束,持有股票时的最大收益
  • dp[i][1] : 表示第 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] - fee)

初始化

这里只需初始化第 1 天结束,持有股票和不持有股票时的最大收益即可。(dp[0][0]dp[0][1]

返回值

题目要求的是最大收益,最终结果存储在 dp[n-1][1]中(最后一天结束,持有股票状态无意义)

代码实现

cpp 复制代码
class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int n = prices.size();
        vector<vector<int>> dp(n, vector<int>(2, 0));
        dp[0][0] = -prices[0];
        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] - fee);
        }
        return dp[n - 1][1];
    }
};

三、买卖股票的最佳时机 III

题目解析

给定一个数组 procesproces[i]表示第 i 天的股票价格;

约束条件

  • 不能同时参与多笔交易(已有股票就不能再买入了)
  • 最多只能进行 2 笔交易

算法思路

这道题没有交易冷冻期,交易手续费之类的;要求只能进行 2 笔交易

对于第 i 天结束,这个状态就有 6种:

进行了 0 次交易:持有股票(买入状态)不持有股票(卖出状态)

进行了 1 次交易:持有股票(买入状态)不持有股票(卖出状态)

进行了 2 次交易:持有股票(买入状态)不持有股票(卖出状态)

一次交易:股票买入 - 股票卖出

这里当股票卖出之后,认为此次交易才算完成

状态表示

  • f[i][0]:第 i 天结束,进行了 0 次交易,处于 买入 状态的最大利润
  • f[i][1]:第 i 天结束,进行了 1 次交易,处于 买入 状态的最大利润
  • f[i][2]:第 i 天结束,进行了 2 次交易,处于 买入 状态的最大利润
  • g[i][0]:第 i 天结束,进行了 0 次交易,处于 卖出 状态的最大利润
  • g[i][1]:第 i 天结束,进行了 1 次交易,处于 卖出 状态的最大利润
  • g[i][2]:第 i 天结束,进行了 2 次交易,处于 卖出 状态的最大利润

状态转移方程

  • f[i][0] = max(f[i-1][0], g[i-1][0] - prices[i])
  • f[i][1] = max(f[i-1][1], g[i-1][1] - prices[i])
  • f[i][2] = max(f[i-1][2], g[i-1][2] - prices[i])
  • g[i][0] = g[i-1][0]
  • g[i][1] = max(g[i-1][1], f[i-1][0] + prices[i])
  • g[i][2] = max(g[i-1][2], f[i-1][1] + prices[i])

初始化

这里初始化 第 1 天结束时,0 次交易,处于 买入 状态的最大收益即可(第一天结束,进行 0 笔交易,处于卖出状态)

为了不影响最终结果,第 1 天结束,进行 1、2 笔交易最大收益 都设置成 -0x3f3f3f

返回值

要求最大收益,最终结果(第 n 天结束,进行了 0、1、2次交易,处于 卖出(不持有股票)的最大收益)

max(g[n-1][0], g[n-1][1], g[n-1][2])

代码实现

cpp 复制代码
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> f(n, vector<int>(3, 0));
        vector<vector<int>> g(n, vector<int>(3, 0));
        f[0][0] = -prices[0];
        f[0][1] = f[0][2] = g[0][1] = g[0][2] = -0x3f3f3f;
        for (int i = 1; i < n; i++) {
            f[i][0] = max(f[i - 1][0], g[i - 1][0] - prices[i]);
            f[i][1] = max(f[i - 1][1], g[i - 1][1] - prices[i]);
            f[i][2] = max(f[i - 1][2], g[i - 1][2] - prices[i]);

            g[i][0] = g[i - 1][0];
            g[i][1] = max(g[i - 1][1], f[i - 1][0] + prices[i]);
            g[i][2] = max(g[i - 1][2], f[i - 1][1] + prices[i]);
        }
        return max(max(g[n - 1][0], g[n - 1][1]), g[n - 1][2]);
    }
};

四、买卖股票的最佳时机 IV

题目解析

给定一个数组 proces和一个整数 kproces[i]表示第 i 天的股票价格,k 表示最多的交易次数

约束条件

  • 不能同时参与多笔交易(已有股票就不能再买入了)
  • 最多只能进行 k 笔交易

算法思路

对于第 i 天结束,这个状态有 2*k 种,很显然使用有限的状态是表示不过来了;

这里就可以使用二维数组(甚至三维)来表示:

状态表示

  • f[i][j] :第 i 天结束,进行了 j 次交易,处于 买入 状态的最大利润
  • g[i][j] :第 i 天结束,进行了 j 次交易,处于 卖出 状态的最大利润

状态转移方程

  • 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])

注意 : 在填 g[i][0]时,会用到 f[i-1][-1](越界);这里需要进行特殊判断

初始化

这里初始化 第 1 天结束时,0 次交易,处于 买入 状态的最大收益(-prices[i])、第一天结束,进行 0 笔交易,处于卖出状态,最大收益为 0

为了不影响最终结果,第 i(i > 0) 天结束,进行 0~k 笔交易最大收益 都设置成 -0x3f3f3f

最终结果

求最大利润,最终结果就应该是 第 n-1 天结束,进行 0~k 笔交易,处于卖出状态的最大利润

代码实现

cpp 复制代码
class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        vector<vector<int>> f(n, vector<int>(k + 1, 0));
        vector<vector<int>> g(n, vector<int>(k + 1, 0));
        for (int i = 1; i <= k; i++)
            f[0][i] = g[0][i] = -0x3f3f3f;
        f[0][0] = -prices[0];
        g[0][0] = 0;
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= k; j++) {
                f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]);
                g[i][j] = g[i - 1][j];
                if (j > 0)
                    g[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + prices[i]);
            }
        }
        int ret = -0x3f3f3f;
        for (int i = 0; i <= k; i++)
            ret = max(ret, g[n - 1][i]);
        return ret;
    }
};

本篇文章到这里就结束了,感谢支持

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws

相关推荐
武帝为此20 分钟前
【数据清洗缺失值处理】
python·算法·数学建模
Halo_tjn1 小时前
Java 基于字符串相关知识点
java·开发语言·算法
念越1 小时前
算法每日一题 Day08|双指针法解决三数之和
算法·力扣
黎阳之光2 小时前
黎阳之光透明管理:视频孪生重构智慧仓储新范式
人工智能·算法·安全·重构·数字孪生
CappuccinoRose3 小时前
回溯法 - 软考备战(四十三)
算法·排列组合·路径·n皇后·子集·解数独·岛屿
AC赳赳老秦3 小时前
OpenClaw进阶技巧:批量修改文件内容、替换关键词,解放双手
java·linux·人工智能·python·算法·测试用例·openclaw
Robot_Nav3 小时前
Shape-Aware MPPI(SA MPPI)算法:基于RC-ESDF的任意形状机器人实时轨迹优化
算法·机器人·sa-mppi
踩坑记录4 小时前
leetcode hot100 118. 杨辉三角 easy 动态规划
leetcode·动态规划
小O的算法实验室4 小时前
2026年ESWA,自适应基于排序的协同进化学习粒子群算法+边缘计算服务器部署,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
cpp_25014 小时前
P1832 A+B Problem(再升级)
数据结构·c++·算法·动态规划·题解·洛谷·背包dp