题意:有一支股票每天的价格波动,请在给定的时间内完成k次交易使收益最大,一次交易代表买入再卖出,交易不能重叠(必须卖完之后在买)。
题解:我们首先设global[i][j]为到第i天为止交易j次的最大收益。
因为最后一次交易要么在第i天卖出,要么在之前卖出。在之前卖出的最大收益显然是global[i-1][j],而要求第i天卖出的最大收益我们需要枚举在前面哪一天买进。可以得到转移方程:
global[i][j] = max{global[i-1][j], max{global[k][j-1]+p[i]-p[k], 0<=k<=i}};
以上我们将k=i单独取出来则可以化简为:
global[i][j] = max{global[i-1][j], global[i][j-1], max{global[k][j-1]+p[i]-p[k], 0<=k<=i-1}};
以上为N^2*k的复杂度。
但是我们仔细观察最后一个max式子可以发现这个有明显的递推关系。它的意义在于仅在第i天卖出的最大收益。
则我们以空间换时间,再新建一个数组local[i][j]代表前i天交易j次,且第j次交易必须在第i天卖出的最大收益。
则有转移方程:
local[i][j] = max{global[k][j-1]+p[i]-p[k], 0<=k<=i},我们将p[i]-p[k] = p[i]-p[i-1]+p[i-1]-p[k]。
得
local[i][j] = max{global[k][j-1]+p[i-1]-p[k], 0<=k<=i}+p[i]-p[i-1],
再进一步
local[i][j] = max{global[i][j-1], max{global[k][j-1]+p[i-1]-p[k], 0<=k<=i-1}+p[i]-p[i-1]},
其中,max{global[k][j-1]+p[i-1]-p[k], 0<=k<=i-1}就是local[i-1][j]。
则有最终的转移方程:
local[i][j] = max{global[i][j-1], local[i-1][j]+p[i]-p[i-1]}
global[i][j] = max{global[i-1][j], local[i][j]}
具体实现时可以使用滚动数组节省空间。
代码如下:
class Solution {
public:
int quickSolve(vector<int>& prices) {
int maxProfit = 0;
for(int i = 1;i < prices.size();i++) {
if(prices[i] > prices[i-1]) {
maxProfit += prices[i]-prices[i-1];
}
}
return maxProfit;
}
int maxProfit(int k, vector<int>& prices) {
int pSize = prices.size();
if(k >= pSize/2) {
//相当于可以进行无限次交易
return quickSolve(prices);
}
vector<int> local(k+1, 0);
vector<int> global(k+1, 0);
for(int i = 1;i < pSize;i++) {
int diff = prices[i]-prices[i-1];
for(int j = 1;j <= k;j++) {
local[j] = max(global[j-1], local[j]+diff);
global[j] = max(global[j], local[j]);
}
}
return global[k];
}
};