188. Best Time to Buy and Sell Stock IV(一个小结)

来源:互联网 发布:2016云计算技术大会 编辑:程序博客网 时间:2024/06/03 20:04

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).

Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.


AC代码:

class Solution {public:    int maxProfit(int k, vector<int>& prices) {        int n=prices.size();        if(n<=1)return 0;        else if(k>n/2){            int res=0;            for(int i=1;i<n;i++)                res+=max(prices[i]-prices[i-1],0);            return res;        }        else{            int tmp_max;            vector<vector<int>>f(k+1,vector<int>(n,0));            for(int i=1;i<=k;i++){                tmp_max=-prices[0];                for(int j=1;j<n;j++){                    f[i][j]=max(f[i][j-1],tmp_max+prices[j]);                    tmp_max=max(tmp_max,f[i-1][j]-prices[j]);                }            }            return f[k][n-1];        }    }};


以下来自Discuss:

Clearly DP is one of solutions to this kind of problems. I will like to summarize how to start and analyze for beginners:

Goal: find the max profit at day n-1 with at most k transactions.

Here we know we have two keys: day and transaction, of course it depends on past history (previous day with certain transactions), so if you try to solve this in a pure math. calculation and struggle with so many possibilities, that means we had better switch to consider how to build the math. model.

Notations:

f[k][i]: max profit up to day i (included) with at most k transactions (global optimal objective)
g[k][i]: max profit up to day i (included) with at most k transactions AND we sell at day i (local optimal objective, why local? think about it!)

DP recursive formula:
(1). f[k][i] = max ( f[k][i-1], g[k][i] )
(2). g[k][i] = max_{j=0,...,i-1} (p[i] - p[j] + f[k-1][j-1])
// (1): this means if we don't sell at day i, then f[k][i] is just f[k][i-1]; otherwise f[k][i] will be the max profit that we can achieve if we sell at day i
// (2): since we will sell at day i anyway, that means we need to buy at a certain previous day, for a particular j, the best we can have is p[i] - p[j] + f[k-1][j-1].

With these formulas, we can start to code by computing and storing all the information of f[k][i] and g[k][i]. One trick is that for (2), the max is easy to handle because we compute g[k][i] for i=0,1,2,... (with fixed k), so use one temp variable to keep updating the value will be enough.

If we think carefully, (1) and (2) only use the information on k-1, that means we can reduce the space complexity O(k*n) to O(n) pretty easily.

Can we reduce the space to be O(k)? The answer is yes. Of course, the formula (2) looks a bit ugly. Let's rewrite it a bit:
(2)'. g[k][i] = max ( g[k][i-1], f[k-1][i-1]) ) + p[i] - p[i-1].

Now let me put (1) and (2)' together:
(1). f[k][i] = max ( f[k][i-1], g[k][i] )
(2)'. g[k][i] = g[k][i-1], f[k-1][i-1]) + p[i] - p[i-1]
It's a lot simpler, right? The key is to get the current state (k,i), we only need the k-1 or i-1 information. So in the code, we have two loops but with outer: i-loop and inter: k-loop. This will makes space to be O(k). If k is way more small than n, then you can consider it's a good improvement.

You might come up (1) and (2)' directly, but here I just want to explain what happened in peterleetcode's post. So I start with his formulation. Finally, attach my code (may not be optimized) Whoops, this code is for IV, but should work for III case also.

class Solution {public:    int maxProfit(int k, vector<int>& prices) {        int n=prices.size();        if (n<2) return 0;        if (k>=n/2) { // buy-sell-II case, unlimited            int maxProfit=0;            for (int i=1; i<n; ++i) {                if (prices[i]>prices[i-1]) maxProfit += prices[i] - prices[i-1];            }            return maxProfit;        }        // if k<n/2, use DP approach but only O(k) space        vector<int> f(k+1,0), g(k+1,0);        for (int i=1; i<n; ++i) {            int diff = prices[i] - prices[i-1], temp = f[0];            for (int kk=1; kk<=k; ++kk) {                g[kk] = max(g[kk], temp) + diff;                temp=f[kk];                f[kk] = max(f[kk], g[kk]);            }        }        return f[k];    }};

PS: be careful in (2)', we have f[k-1][i-1], so before updating f[kk], we should save it for later use. Or I believe you can use different order of k to remove this "ugly" part.


阅读全文
0 0
原创粉丝点击