一、问题分析

由于最多可以完成两笔交易,因此在任意一天结束之后,我们都会处于以下五个状态中的一种:

  1. 未进行过任何操作;
  2. 只进行过一次买操作;
  3. 进行了一次买操作和一次卖操作,即完成了一笔交易;
  4. 在完成了一笔交易的前提下,进行了第二次买操作;
  5. 完成了全部两笔交易;

第一个状态的利润显然为0,所以我们可以不用将其记录;

而剩余几个状态分别将它们的最大利润记为:buy1sell1buy2sell2

二、动态方程

如果已知第i-1天结束后这四个状态,就可以通过状态方程推导第i天的这四个状态:

理解buy1buy1 = max(buy1, -prices[i])

  1. 第i天可以不进行任何操作,继续保持buy1
  2. 也可以在未进行任何操作的前提下,以price[i]买入;

理解sell1sell1 = max(sell1, buy1 + prices[i])

  1. 第i天可以不进行任何操作,继续保持sell1
  2. 也可以在只进行过一次买操作的前提下,以price[i]价格卖出股票;

理解buy2buy2 = max(buy2, sell1 - prices[i])

  1. 第i天可以不进行任何操作,继续保持buy2
  2. 也可以在买卖过一次的前提下,以price[i]价格再次买入;

理解sell2sell2 = max(sell2, buy2 + prices[i])

  1. 第i天可以不进行任何操作,继续保持sell2
  2. 也可以在buy2的前提下,以price[i]价格卖出;

三、理解初始边界条件

考虑第i = 0天时的四个状态

  • buy1:在第一天以prices[0]的价格买入,因此buy1 = -price[0]

  • sell1:在第一天买入并卖出,因此sell1 = 0

  • buy2:在第一天买入并卖出后,再次以price[0]的价格买入,因此buy2 = -price[0]

  • sell2:在第一天买入并卖出,再次买入并卖出,因此sell2 == 0

四、最终应该以sell2作为返回值

  1. 首先buy1只买不卖,buy2sell1的前提下还要再买一次,这两个肯定不会是最大收益;
  2. 再考虑sell1sell2,如果最优的情况对应的是恰好一笔交易,那么它也会因为我们在转移时允许在同一天买入并且卖出这一宽松的条件下,很容易由sell1转移至sell2,因此sell2才可以代表最大利益;

五、Swift代码示例

public class Solution {
   /**
    * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
    * 两次交易所能获得的最大收益
    * @param prices int整型一维数组 股票每一天的价格
    * @return int整型
    */
   func maxProfit(_ prices: [Int]) -> Int {
       let n = prices.count
       guard n > 0 else { return 0 }
     
       var buy1 = -prices[0], buy2 = -prices[0]
       var sell1 = 0, sell2 = 0

       for i in 1 ..< n {
           buy1 = max(buy1, -prices[i])
           sell1 = max(sell1, buy1 + prices[i])
           buy2 = max(buy2, sell1 - prices[i])
           sell2 = max(sell2, buy2 + prices[i])
       }
       return sell2
   }
}