一、題目描述
給定一個數組,它的第 i 個元素是一支給定的股票在第 i 天的價格。
設計一個算法來計算你所能獲取的最大利潤。你最多可以完成 k 筆交易。
注意: 你不能同時參與多筆交易(你必須在再次購買前出售掉之前的股票)。
示例 1:
輸入: [2,4,1], k = 2 輸出: 2 解釋: 在第 1 天 (股票價格 = 2) 的時候買入,在第 2 天 (股票價格 = 4) 的時候賣出,這筆交易所能獲得利潤 = 4-2 = 2 。
示例 2:
輸入: [3,2,6,5,0,3], k = 2 輸出: 7 解釋: 在第 2 天 (股票價格 = 2) 的時候買入,在第 3 天 (股票價格 = 6) 的時候賣出, 這筆交易所能獲得利潤 = 6-2 = 4 。 隨后,在第 5 天 (股票價格 = 0) 的時候買入,在第 6 天 (股票價格 = 3) 的時候賣出, 這筆交易所能獲得利潤 = 3-0 = 3 。
二、問題分析
1、這是比較經典和復雜的動態規划問題,因為需要同時記錄兩個狀態,對狀態的定義也比較嚴格,值得好好分析
2、定義狀態:buy[i][j] 在第i天交易正好是第j次買入時能夠獲得的最大利潤;sell[i][j] 在第i天交易正好是第j次賣出時能夠獲得的最大利潤
3、狀態轉移:buy[i][j]=max(buy[i-1][j],sell[i-1][j-1]-prices[i]);sell[i][j]=max(sell[i-1][j],buy[i-1][j]+prices[i]);
4、初始狀態:buy[0~n-1][0]=INT_MIN,sell[0~n-1][0]=0;
5、最終狀態:sell[n-1][k]
6、其實可以省略i,只保留交易次數,需要注意的是當交易次數大於等於天數的一半,就可以把所有上升的天數相加
三、AC代碼
class Solution { public: int maxProfit(int k, vector<int>& prices) { int n = prices.size(); if (n < 2 || k < 1)return 0; if (k >= n / 2)return getMax(prices); vector<int>buy(k + 1, INT_MIN), sell(k + 1,0); int i, j; for (i = 0; i < n; ++i) { for (j = 1; j <= k; ++j) { buy[j] = max(buy[j], sell[j - 1] - prices[i]); sell[j] = max(sell[j], buy[j] + prices[i]); } } return sell[k]; } private: int getMax(vector<int>&prices) { int res = 0; for (int i = 1; i < prices.size(); ++i) { if (prices[i] > prices[i - 1]) res += (prices[i] - prices[i - 1]); } return res; } };