买卖股票的最佳时机专题(动态规划)

发布时间 2023-04-24 19:24:57作者: 失控D大白兔

一. 买卖一次(简单)

dp[i]表示第i天卖出时的最大值,可以用滚动变量优化

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<int> dp(n+1);
        int min_= INT_MAX;
        for(int i=0;i<n;i++){
            dp[i+1]=max(dp[i],prices[i]-min_);
            min_=min(min_,prices[i]);//记录已经遍历的最小值
        }
        return dp[n];
    }
};

二. 买卖无数次(中等)

dp[i][j]表示第i天持股状态j下的最大收益,可以用滚动变量优化

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        //dp[i][j]表示第i天持股状态j下的最大收益
        int n = prices.size();
        int dp[n+1][2];
        dp[0][0] = 0; dp[0][1] = -prices[0];//边界条件
        for(int i=0;i<n;i++){
            dp[i+1][0] = max(dp[i][0],dp[i][1]+prices[i]);//第i天不持股
            dp[i+1][1] = max(dp[i][1],dp[i][0]-prices[i]);//第i天持股
        }
        return dp[n][0];
    }
};
贪心对大于0的差值求和(特解)
class Solution {
public:
    int maxProfit(vector<int>& prices) {   
        int ans = 0;
        int n = prices.size();
        for (int i = 1; i < n; ++i) {
            ans += max(0, prices[i] - prices[i - 1]);
        }
        return ans;
    }
};

三. 最多进行两笔交易(困难)

dp[i][j][k]表示第i天持有状态j交易次数k下的最大利润

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();//将买入视作进行了一次交易,然后卖出就可以从当前买入状态进行转移
        int dp[n+1][2][3];//dp[i][j][k]表示第i天持有状态j交易次数k下的最大利润
        for(int i=0;i<n;i++)
            dp[i+1][0][0] = 0;//多余边界初始化0
        for(int j=0;j<2;j++){
            dp[0][0][j+1] = 0;//多余边界初始化0
            dp[0][1][j+1] = -prices[0];//这里直接给初值,没必要再使用多余空间
        }
        for (int i = 0; i < n; i++) {
            for(int j=0;j<2;j++){
                dp[i+1][1][j+1] = max(dp[i][1][j+1],dp[i+1][0][j]-prices[i]);//第j次买入
                dp[i+1][0][j+1] = max(dp[i][0][j+1],dp[i+1][1][j+1]+prices[i]);//第j次卖出
            }
        }
        return dp[n][0][2];
    }
};
四个滚动变量优化 ``` class Solution { public: int maxProfit(vector& prices) { int n = prices.size();//将持有视作进行了一次交易,然后卖出就可以从持有状态进行转移 int hold1 = -prices[0], sell1 = 0; int hold2 = -prices[0], sell2 = 0; for (int i = 1; i < n; ++i) { hold1 = max(hold1, -prices[i]);//进行一次交易的持有状态 sell1 = max(sell1, hold1 + prices[i]);//进行一次交易的卖出状态 hold2 = max(hold2, sell1 - prices[i]);//进行两次交易的持有状态 sell2 = max(sell2, hold2 + prices[i]);//进行两次交易的卖出状态 } return sell2; } }; ```

四. 最多进行k笔交易(困难)

dp[i][j][k]表示第i天持有状态j交易次数k下的最大利润

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();//将买入视作进行了一次交易,然后卖出就可以从当前买入状态进行转移
        int dp[n+1][2][k+1];//dp[i][j][k]表示第i天持有状态j交易次数k下的最大利润
        for(int i=0;i<n;i++)
            dp[i+1][0][0] = 0;//多余边界初始化0
        for(int j=0;j<k;j++){
            dp[0][0][j+1] = 0;//多余边界初始化0
            dp[0][1][j+1] = -prices[0];//这里直接给初值,没必要再使用多余空间
        }
        for (int i = 0; i < n; i++) {
            for(int j=0;j<k;j++){
                dp[i+1][1][j+1] = max(dp[i][1][j+1],dp[i+1][0][j]-prices[i]);//第j次买入
                dp[i+1][0][j+1] = max(dp[i][0][j+1],dp[i+1][1][j+1]+prices[i]);//第j次卖出
            }
        }
        return dp[n][0][k];
    }
};

五. 买卖无限次含冷冻期一天

dp[i][j]表示第i天状态为j的情况下最大利润

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        int dp[n+1][3];
        for(int i=0;i<3;i++)
            dp[0][i] = 0;//多余边界初始化0
        dp[0][0] = -prices[0]; //直接赋初值,使能进入循环
        for (int i = 0; i < n; ++i) {
            dp[i+1][0] = max(dp[i][0],dp[i][2]-prices[i]);//持有股票状态
            dp[i+1][1] = dp[i][0] + prices[i];//卖出股票且在冷冻期
            dp[i+1][2] = max(dp[i][2], dp[i][1]);//卖出股票且不在冷冻期
        }
        return max(dp[n][1],dp[n][2]);
    }
};

六.买卖无限次含手续费

与题二基本一致

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        //dp[i][j]表示第i天持股状态j下的最大收益
        int n = prices.size();
        int dp[n+1][2];
        dp[0][0] = 0; dp[0][1] = -prices[0]-fee;//边界条件
        for(int i=0;i<n;i++){
            dp[i+1][0] = max(dp[i][0],dp[i][1]+prices[i]);//第i天不持股
            dp[i+1][1] = max(dp[i][1],dp[i][0]-prices[i]-fee);//第i天持股
        }
        return dp[n][0];
    }
};