动态规划典中典之股票买卖问题

82 阅读2分钟

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

  1. 确定是最值问题,解题过程可枚举,买入、卖出、观望
  2. 确定动作背后的状态:买入=>花钱、卖出=>收钱、观望=>不变 ==> 现金流就是状态
  3. 定义状态数据dp[i]为第i天的最大现金流,分为两种子状态,当前还持有股票或者已没有股票,设为dp_yes[i]和dp_no[i]
  4. 最后一步:
    • 最后一天没有股票的最大现金流,就是前一天没有股票的最大现金流或者前一天持有股票的最大现金流+最后一天股票的价格;
    • 最后一步的子情况:前一天持有股票的最大现金流就是前前天持有股票的最大现金流或者前前天没有股票,前一天买入的最大现金流
  5. 确定状态
  6. 确定状态转移方程:
    • dp_yes[i] = max(dp_yes[i-1], dp_no[i-1]-prices[i])
    • dp_no[i] = max(dp_no[i-1], dp_yes[i-1]+prices[i])
  7. 确定边界条件:dp_yes[0] = - prices[0] ; dp_no[0] = 0
  8. 确定初值(最坏情况): 最坏情况股票一直跌,此时只有一直不买入才不会亏损,收益为0
class Solution {
public:
    int maxProfit(vector<int>& prices) {

        // ! narrow case 保护
        if(prices.empty()) {
            return 0;
        }
        int day = prices.size();
        // ! 第 i 天有两种状态,手中持有股票或者没有股票
        vector<int> maxProfitHold(day, 0);
        vector<int> maxProfitSell(day, 0);
        maxProfitHold[0] = -prices[0];
        maxProfitSell[0] = 0;
        for(int i = 1; i < day; i++) {
            // 持有股票分两种情况
            // 之前就持有,今天无买入:当前收益 <=> 昨天持有的收益
            // 之前卖掉了,今天才买入:当前收益 <=> 买股票那天的收益 - 今日股价 => max = max(昨天卖掉股票的收益 - 今日股价)
            maxProfitHold[i] = max(maxProfitHold[i-1], maxProfitSell[i-1] - prices[i]);
            // 不持有股票分两种情况
            // 之前就卖了,一直无买入:当前收益 <=> 卖股票那天的收益 => max = max(昨天卖掉股票的收益)
            // 之前一直持有,今天才卖掉:当前收益 <=> 昨天持有的收益 + 今日股价
            maxProfitSell[i] = max(maxProfitSell[i-1], maxProfitHold[i-1] + prices[i]);
        }
        return maxProfitSell[day-1];
    }
};