动态规划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];
    }
相关推荐
v_for_van2 小时前
力扣刷题记录6(无算法背景,纯C语言)
c语言·算法·leetcode
-To be number.wan2 小时前
算法学习日记 | 双指针
c++·学习·算法
样例过了就是过了2 小时前
LeetCode热题100 最大子数组和
数据结构·算法·leetcode
铸人2 小时前
再论自然数全加和 - 欧拉伽马常数
数学·算法·数论·复数
m0_531237173 小时前
C语言-变量,枚举常量,字符串,打印类型,转义字符
c语言·数据结构·算法
zyeyeye3 小时前
自定义类型:结构体
c语言·开发语言·数据结构·c++·算法
俩娃妈教编程3 小时前
2023 年 03 月 二级真题(1)--画三角形
c++·算法·双层循环
niuniudengdeng3 小时前
一种基于高维物理张量与XRF实景复刻的一步闭式解工业级3D打印品生成模型
人工智能·python·数学·算法·3d
哈库纳玛塔塔4 小时前
公元前日期处理的两种方案
数据库·算法·mybatis