LeetCode 188. Best Time to Buy and Sell Stock IV

来源:互联网 发布:儿童电动牙刷价格淘宝 编辑:程序博客网 时间:2024/06/05 02:28

              是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 100000000typedef 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] ;             }};



0 0
原创粉丝点击