股票买卖问题

一般化,设dp[i][j][s]表示第i天、至多交易了j次、手上有s=0或1股股票时的最大利润。

  • 第i天这一维当然要有,手上的股票数s这一维不能少,若没有交易数限制可省掉j这一维。

  • 有交易数限制时,可以买时算新交易改变j、也可卖时算新交易改变j,不妨买时算新交易。

  • 有交易费用时,可以买时算费用、也可卖时算费用,不妨买时算费用、跟买股票一起花钱。

  • 有交易冷却天数限制时,没法像通常dp[i][][]=dp[i-1][][]...那样省掉i这一维


非dp解:只买卖一次,若在第i天卖,应在[0,i)天最便宜时买

非dp解:可以无限次购买,相隔两数有利可图就购买

dp解同ii题,买时加上费用

int maxProfit(vector<int>& prices, int fee) {
    // 设dp[i][s]表示第i天、手上有s=0或1股股票时的最大利润
    // 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 /*买股票*/)
    // 初始dp[-1][0]=0,dp[-1][1]=INT_MIN
    // dp[i][]只依赖dp[i-1][],去掉i这维
    vector<int> dp = { 0, INT_MIN };
    for (int price : prices) {
        int dp0 = dp[0];
        dp[0] = max(dp0, dp[1] + price);
        dp[1] = max(dp[1], dp0 - price - fee);
    }
    return dp[0];
}
int maxProfit(int k, vector<int>& prices) {
    const int N = prices.size();
    if (k == 0 || N < 2) return 0;
    // k足够大时,相当于对交易次数无限制
    if (k >= N/2) return maxProfitInfK(prices);
    
    // 设dp[i][j][s]表示第i天、至多交易了j次、手上有s=0或1股股票时的最大利润
    // dp[i][j][0] = max(dp[i-1][j][0], dp[i-1][j][1] + prices[i] /*卖股票*/)
    // dp[i][j][1] = max(dp[i-1][j][1], dp[i-1][j-1][0] - prices[i] /*买股票,新交易*/)
    // 初始dp[-1][j][0]=0,dp[-1][j][1]=INT_MIN
    // dp在i这维上只依赖于i-1项,去掉i这维
    // 降维后,要让dp[j-1][]表示旧状态d,j要从右往左遍历
    vector<vector<int>> dp(k + 1, vector<int>({ 0, INT_MIN }));
    for (int price : prices) {
        for (int j = k; j >= 1; j--) {
            dp[j][0] = max(dp[j][0], dp[j][1] + price);
            dp[j][1] = max(dp[j][1], dp[j-1][0] - price);
        }
    }
    return dp[k][0];
}

int maxProfitInfK(vector<int>& prices) {
    // 可以无限次购买,相隔两数有利可图就购买
    const int N = prices.size();
    int ans = 0;
    for (auto i = 0; i < N - 1; i++) {
        if (prices[i] < prices[i+1]) {
            ans += prices[i+1] - prices[i];
        }
    }
    return ans;
}
int maxProfit(vector<int>& prices) {
    // 设dp[i][s]表示第i天、手上有s=0或1股股票时的最大利润
    // dp[i][0] = max(dp[i-1][0], dp[i-1][1]+prices[i] /*卖股票*/)
    // dp[i][1] = max(dp[i-1][1], dp[i-2][0]-prices[i] /*买股票, cooldown=1天*/)
    // 初始dp[-1][0]=0,dp[-1][1]=INT_MIN;dp[-2][0]=0,dp[-2][1]=INT_MIN
    // 递推式在i这维上只依赖i-1项、i-2项
    vector<int> prev2 = { 0, INT_MIN };
    vector<int> prev1 = { 0, INT_MIN };
    for (int price : prices) {
        vector<int> curr(2);
        curr[0] = max(prev1[0], prev1[1] + price);
        curr[1] = max(prev1[1], prev2[0] - price);
        prev2 = prev1;
        prev1 = curr;
    }
    return prev1[0];
}