Leetcode 188. Best Time to Buy and Sell Stock IV
Problem:
Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most k transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
Example 1:
Input: [2,4,1], k = 2 Output: 2 Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.
Example 2:
Input: [3,2,6,5,0,3], k = 2 Output: 7 Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4. Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Solution:
终于来到了这道赫赫有名的动态规划问题。首先如果k大于数组长度,则可以轻松的用动态规划解决,在此不加赘述。我们要解决的是k小于数组长度的情况下,如何使用动态规划。这道题之所以难是因为它是有两种状态的互相转移。此题和Leetcode 801有相似之处。对于某一天的交易,可能有两种情况,即卖出手中持有的股票或继续持有。这里维护两个数组local和global。local[i][j]表示最后一次买卖在第i天卖出,同时交易次数小于等于j次的最大收益,global[i][j]表示前i天完成小于等于j次交易的最大收益。因此global[i][j]就很容易得到global[i][j] = max(global[i-1][j],local[i][j]),即i-1天进行j次交易的最大收益和第i天卖出股票的收益的最大值。难点在于local[i][j]的计算,local[i][j]可以分为两部分,对于第一部分global[i-1][j-1] + max(diff,0),可以理解为前一天进行j-1次交易的收益加上从昨天到今天的收益,如果收益为负数,则理解为当天买当天卖,不赚也不赔但交易次数加1,如果赚钱则更好。第二部分local[i-1][j] + diff可以理解为前一天卖出股票的收益加上今天和昨天的收益差,那么为什么不是local[i-1][j-1]+diff呢,因为这里相当与第i-1天卖出的交易变为第i天卖出,所以交易次数不变。
Code:
1 class Solution { 2 public: 3 int maxProfit(int k, vector<int>& prices) { 4 int m = prices.size(); 5 if(k >= m){ 6 int result = 0; 7 for(int i = 0;i < m-1;++i){ 8 int dif = prices[i+1]-prices[i]; 9 result += (dif>0 ? dif : 0); 10 } 11 return result; 12 } 13 vector<vector<int>> local(m,vector<int>(k+1)); 14 vector<vector<int>> global(m,vector<int>(k+1)); 15 for(int i = 1;i != m;++i){ 16 int diff = prices[i] - prices[i-1]; 17 for(int j = k;j >= 1;--j){ 18 local[i][j] = max((global[i-1][j-1] + max(diff,0)),local[i-1][j] + diff); 19 global[i][j] = max(global[i-1][j],local[i][j]); 20 } 21 } 22 return global[m-1][k]; 23 } 24 };