【必備演算法】動態規劃:一個思路解決六道股票問題

A minor發表於2020-11-19

買賣股票系列一共有6道題,都是不斷交易一隻股票(股價通過price[]給出,陣列長度表示可以交易的天數)然後求最大利潤:

現在我們要通過一種動態規劃的思路去通解上面六道題!


我們都知道,動態規劃的第一步是狀態定義,當成功且合適的定義了狀態,一道動態規劃問題就解決一半了。那上面的股票問題如何定義狀態呢?

因為最後求的都是最大利潤,所以狀態的含義肯定是maxprofit。但應該定義成幾維狀態呢?我們下面就從一維到三維逐一嘗試…

1.一維狀態:maxprofit[i]

  • 狀態定義:MP[i]。第i天的最大利潤,取值[0, n)
  • 狀態方程:對於股票無非就兩種操作,買入和賣出
    • 買入:MP[i] = MP[i - 1] + (-p[i])
    • 賣出:MP[i] = MP[i - 1] + (p[i])
  • 最終狀態:MP[n - 1]。第n天的最大利潤

問題:因為只能持有一股,所以買入和賣出的前提分別是未持有和持有,但是隻用這一位 i,根本就沒法知道是否持有啊,所以無法正確進行狀態遞推,所以只用一維不太行…

2.二維狀態:maxprofit[i][j]

  • 狀態定義:MP[i][j] 。第 i 天未持有股票(j=0)或持有股票(j=1)的最大利潤
    • i表示第i天,取值[0, n)
    • j表示當前天是否持有股票,取值為 0或1
  • 狀態方程:第i天時有兩種情況,有股票和沒股票。
    • 第一種情況:我第i天沒有股票,即狀態 MP[i][0]
      • MP[i][0] = MP[i-1][0] 表示我沒股票不操作

      • MP[i][0] = MP[i - 1][1] + p[i] 表示我賣出股票

        ==> 然後再對這兩種情況情況求最值,即MP[i][0] = max(MP[i-1][0], MP[i - 1][1] + p[i])

    • 第二種情況:我第i天有1股,即狀態 MP[i][1]
      • MP[i][1] = MP[i-1][1] 表示我持股票不操作

      • MP[i][0] = MP[i - 1][0] - p[i] 表示我買入股票

        ==> 然後再對這兩種情況情況求最值,即MP[i][1] = max(MP[i-1][1], MP[i - 1][0] - p[i])

  • 最終狀態:MP[n-1][0]。i=n-1沒什麼說的,j=0是因為市場都熄火了,你還持有著股票(j=1)肯定是不值的,就算虧了也要賣掉回點老本

問題:對於前三道題(交易1次,無數次,2次)可以這麼搞,但是如果設定只可以交易K次,那我在狀態遞推時怎麼知道前面已經交易多少次,接下來還能不能交易了?所以二維狀態雖然可行,但是不夠通用…

3.三維狀態:maxprofit[i][k][j]

  • 狀態定義:MP[i][k][j] 。表數第 i 天且已經交易了k次的時,未持有和持有股票的最大利潤

    • i表示第i天,取值[0, n)
    • k表示到今天(第i天)已經交易了k次,取值 [0, K]
    • j表示當前天是否持有股票,取值為 0或1
  • 狀態方程:同上,第i天的時候也是分為兩種情況,未持有股票和持有股票。

    • 第一種情況:我第 i 天沒有股票且交易k次 ,即狀態MP[i][k][0]

      • MP[i][k][0] = MP[i-1][k][0] 表示我沒股票不操作

      • MP[i][k][0] = MP[i - 1][k-1][1]+ p[i] 表示我賣出股票

        ==> 然後再對這兩種情況情況求最值,即MP[i][k][0] = max(MP[i-1][k][0], MP[i - 1][k-1][1] + p[i])

    • 第二種情況:我第 i 天持有股票且交易 k 次,即狀態MP[i][k][1]

      • MP[i][k][1] = MP[i-1][k][1] 表示我持股票不操作

      • MP[i][k][1] = MP[i - 1][k-1][0] - p[i] 表示我買入股票

        ==> 然後再對這兩種情況情況求最值,即MP[i][k][1] = max(MP[i-1][k][1], MP[i - 1][k-1][0] - p[i])

  • 最終狀態:max(MP[n-1][0..K][0])。遍歷交易0-K次看然後找最值

時間複雜度O(N*K*2),空間複雜度也是O(N*K*2)

問題:如果是有冷卻期的話,因為不限制交易次數,所以可以用k記錄是否在冷卻期。

好了,思路分析就到這裡,具體動態規劃程式碼請看:

相關文章