动态规划Day30:买卖股票

121. 买卖股票的最佳时机

贪心法

取左边最小的,记录出现过的最大差值

cpp 复制代码
int maxProfit(vector<int>& prices) {
        int low = INT_MAX;
        int result = INT_MIN;
        for(int price: prices){
            low = min(low, price);
            result = max(result, price - low);
        }
        return result;
    }

动态规划

状态 0 :第 i 天结束后,不持有股票的最大利润。

状态 1 :第 i 天结束后,持有股票的最大利润。

dp[i][0] 表示第 i 天不持有股票的最大利润,dp[i][1] 表示第 i 天持有股票的最大利润。

状态 0(不持有股票)的两种可能:

情况 1:第 i-1 天就不持有股票,第 i 天啥也没做,利润不变 → dp[i][0] = dp[i-1][0]

情况 2:第 i-1 天持有股票,第 i 天卖出了,利润 = 前一天持有股票的利润 + 当天股价 → dp[i][0] = dp[i-1][1] + prices[i]

综上,dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])(取两种情况的最大值)。

状态 1(持有股票)的两种可能:

情况 1:第 i-1 天就持有股票,第 i 天啥也没做,利润不变 → dp[i][1] = dp[i-1][1]

情况 2:第 i 天是第一次买入股票,利润 = - 当天股价(因为买入要花钱,利润为负) → dp[i][1] = -prices[i]

综上,dp[i][1] = max(dp[i-1][1], -prices[i])(取两种情况的最大值,本质是找「最便宜的买入价」)。

初始化状态

第 0 天(第一天):

不持有股票:没买也没卖,利润为 0 → dp[0][0] = 0

持有股票:第一天买入,利润为 -prices[0]dp[0][1] = -prices[0]

cpp 复制代码
int maxProfit(vector<int>& prices) {
        vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
        if(prices.size() == 0){
            return 0;
        }
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        for(int i = 1; i < prices.size(); i++){
            //不持有股票的最大利润
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
            //持有股票的最大利润
            dp[i][1] = max(dp[i - 1][1], -prices[i]);
        }
        return dp[prices.size() - 1][0];
    }

122. 买卖股票的最佳时机 II

贪心法

cpp 复制代码
    int maxProfit(vector<int>& prices) {
        int res = 0;
        for(int i = 1; i < prices.size(); i++){
            if(prices[i] - prices[i - 1] > 0){
                res += prices[i] - prices[i - 1];
            }
        }
        return res;
    }

动态规划

与上题类似,只是允许多次买卖

所以在买入股票需要叠加之前获得的最大利润

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

cpp 复制代码
    int maxProfit(vector<int>& prices) {
       vector<vector<int>> dp(prices.size(), vector<int>(2));
       if(prices.size() == 0){
        return 0;
       }
       dp[0][0] = 0;
       dp[0][1] = -prices[0];
       for(int i = 1; i < prices.size(); 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[prices.size() - 1][0];
    }

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

有五种状态:

没有操作

第一次持有股票

第一次不持有股票

第二次持有股票

第二次不持有股票

cpp 复制代码
    int maxProfit(vector<int>& prices) {
        vector<vector<int>>dp(prices.size(), vector<int>(5));
        if(prices.size() == 0){
            return 0;
        }
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        dp[0][2] = 0;
        dp[0][3] = -prices[0];
        dp[0][4] = 0;
        for(int i = 1; i < prices.size(); i++){
            dp[i][0] = dp[i - 1][0];//不操作一直是0
            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[prices.size() - 1][4];

    }

188. 买卖股票的最佳时机 IV

是上题的扩展,有k次买 k次卖,就有2 * k + 1个状态,第一个状态为不操作,其余是第i次持有,以及第i次不持有

cpp 复制代码
int maxProfit(int k, vector<int>& prices) {
        vector<vector<int>>dp(prices.size(), vector<int>(2*k + 1));
        if(prices.size() == 0){
            return 0;
        }
        for(int i = 1; i < 2*k + 1; i++){
            if(i % 2 == 1){
                dp[0][i] = -prices[0];
            }else {
                dp[0][i] = 0;
            }
        }
        for(int i = 1; i < prices.size(); i++){
            dp[i][0] = 0;
            for(int j = 1; j < 2*k + 1; j++){
                if(j % 2 == 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[prices.size() - 1][2 * k];
    }

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

分成四个状态:

今天持有股票:

继承昨日已买的股票

今日买股票

今天卖出股票

今天继续不买股票(非冷冻期):

昨日冷冻期

昨日非冷冻期

今天冷冻期

cpp 复制代码
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size() <= 1){
            return 0;
        }
        vector<vector<int>> dp(prices.size(), vector<int>(4, 0));
        //四种状态:今天持有股票,今天卖出,今天保持不买(非冷冻期),今天冷冻期
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = 0;
        dp[0][3] = 0;
        for(int i = 1; i < prices.size(); i++){
            dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][2] - prices[i], dp[i - 1][3] - prices[i]));
            dp[i][1] = dp[i - 1][0] + prices[i];
            dp[i][2] = max(dp[i - 1][2], dp[i - 1][3]);
            dp[i][3] = dp[i - 1][1];
        }
        return max(dp[prices.size() - 1][1],max(dp[prices.size() - 1][2], dp[prices.size() - 1][3]));

    }
};

714. 买卖股票的最佳时机含手续费

与第二题类似,只是卖出的时候多扣一个手续费

cpp 复制代码
    int maxProfit(vector<int>& prices, int fee) {
        if(prices.size() <= 1){
            return 0;
        }
        vector<vector<int>>dp(prices.size(), vector<int>(2, 0));
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        for(int i = 1; i < prices.size(); 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[prices.size() - 1][1];
    }
相关推荐
云泽80812 小时前
深入 AVL 树:原理剖析、旋转算法与性能评估
数据结构·c++·算法
Wilber的技术分享13 小时前
【LeetCode高频手撕题 2】面试中常见的手撕算法题(小红书)
笔记·算法·leetcode·面试
邪神与厨二病13 小时前
Problem L. ZZUPC
c++·数学·算法·前缀和
梯度下降中14 小时前
LoRA原理精讲
人工智能·算法·机器学习
IronMurphy14 小时前
【算法三十一】46. 全排列
算法·leetcode·职场和发展
czlczl2002092514 小时前
力扣1911. 最大交替子序列和
算法·leetcode·动态规划
靴子学长15 小时前
Decoder only 架构下 - KV cache 的理解
pytorch·深度学习·算法·大模型·kv
寒秋花开曾相惜15 小时前
(学习笔记)3.8 指针运算(3.8.3 嵌套的数组& 3.8.4 定长数组)
java·开发语言·笔记·学习·算法
Гений.大天才15 小时前
2026年计算机领域的年度主题与范式转移
算法
njidf16 小时前
C++与Qt图形开发
开发语言·c++·算法