是LeetCode 123的升级版,题意也差不多,只是限制了不能超过k次买卖。话说我做到第四题才发现Stock是股票的意思,stone才是石头...
这道题做的挺坎坷了,用了好几种方法,做了一个晚上,最后还是看了题解稍微被提示一下才过的。
一开始我就想到了动态规划的方法,我用d[p][i][j] 来表示区间[i, j] 间至多买卖p次的最大利润。递推公式也很简单,为
d[p][i][j] = max(d[p][i][j] , d[p-1][i][q] + d[1][q+1][j] ) 。而d[1][i][j] 是可以先算出来的,算出来的复杂度为O(n2)。
然而这种动态规划的时间复杂度为O(n4)不用交都知道会超时。不过我还是交了,反而是超出了内存空间。
接下来我发现了d[p][i][j] 的第二维是没有必要的。然后我重新用一个新的数组a[i][j] 来表示区间[i, j] 买卖最多一次的最大利润,上面已经有提到,复杂度为O(n2)。而新的递推公式为,
d[p][j] = max(d[p][j], d[p-1][i-1] + a[i][j] ) ,总的时间复杂度为O(n3)。
然而还是超时了,超时的测试样例为一个k值很大的测试样例。我发现当k大于n/2时,多余的k并没有任何用处。所以我在开始的时候加上了一条 k = min (k , n/2 )。 但这依然改变了不了我超时的结果。
受到四边形不等式的启发,我在想能不能减去第三维不必要的枚举呢?
其实a[i][j] 在j增大的时候,并不是一直在增大。于是我用last[i][j] 来表示j后的第一个j ’ ,使得a[i][j'] > a[i][j]。这样j +1 ~ j’ - 1之间的枚举就能够省去了。计算所有last[i][j] 的时间复杂度为O(n2)。
最后的时间复杂度虽然还是O(n3),但由于last数组的存在可以加速不少。
再次提交发现不超时了,倒是内存反而超了...
无奈之下去看了题解,发现当k足够大的时候,要用到LeetCode 122的方法来做,即不限制买卖次数的情况,真坑...
修改之后终于过了,不过执行的时间基本属于倒数的了...而我在删去last数组之后再提交发现是超时的,说明这步的操作还是有必要的。代码如下,虽然感觉写的很糟糕,勉强能过而已:
const int maxk = 5000 + 5 ;
const int maxn = 5000 + 5;
# define INF 100000000
typedef vector<vector<int> > Matrix ;
Matrix d ;
Matrix a ;
Matrix last ;
class Solution {
public:
int maxProfit2(vector<int>& prices) {
int n = prices.size() ;
if (n <= 1) return 0;
vector<int> a ;
a.push_back(INF) ;
for (int i=0; i<n; i++) a.push_back(prices[i]) ;
a.push_back(-INF) ;
int ans = 0 ;
int buy = 0 ;
for (int i=1; i<=n; i++) {
if (a[i] <= a[i-1]) buy = a[i] ;
else if (a[i] >= a[i+1]) {
ans += a[i] - buy ;
}
}
return ans ;
}
int maxProfit(int k, vector<int>& prices) {
int n = prices.size() ;
if (!n) return 0 ;
if (!k) return 0 ;
if (k > n/2) return maxProfit2(prices) ;
d = Matrix(k+1) ;
a = Matrix(n) ;
last = Matrix(n) ;
for (int i=0; i<=k; i++) {
for (int j=0; j<n; j++) d[i].push_back(0) ;
}
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
a[i].push_back(0) ;
last[i].push_back(-1) ;
}
}
// memset(d, 0, sizeof(d)) ;
// memset(a, 0, sizeof(a)) ;
for (int i=0; i<n; i++) {
int mx = prices[i] ;
for (int j=i+1; j<n; j++) {
a[i][j] = max(a[i][j-1], prices[j] - mx) ;
if (prices[j] < mx) {
mx = prices[j] ;
}
}
}
for (int j=n-1; j>=0; j--) {
int lx = j ;
int lv = a[j][j] ;
for (int i=j; i>=0; i--) {
if (a[i][j] > lv) {
for (int t=lx; t>i; t--) {
last[t][j] = i ;
}
lv = a[i][j] ;
lx = i ;
}
}
}
for (int p=1; p<=k; p++) {
for (int j=1; j<n; j++) {
d[p][j] = d[p-1][j] ;
d[p][j] = max(d[p][j], a[0][j]) ;
int i = j ;
while (i != -1) {
d[p][j] = max(d[p][j], d[p-1][i-1] + a[i][j]) ;
i = last[i][j] ;
}
/* for (int i=0; i<j; i++) {
d[p][j] = max(d[p][j], d[p-1][i] + a[i+1][j]) ;
}*/
}
}
return d[k][n-1] ;
}
};