4 Best Time to Buy and Sell Stock III_Leetcode

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 two transactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

当遇到限制次数以及求最大的要求时,很自然要联想到动规。

动规中不同的状态设计,会有不同的时间复杂度。

本题有两种解法:

(1) 

我最开始想到的是下面这种解法,但是Memory Limit Exceeced.

O(n^2)的解法

很自然的我们会想到记录从开头到第i个字符中进行k次交易能够得到的最大收益,记为dp[i][k].

进行更新:dp[i][k] = max{dp[j][k-1]+maxprofit(j...i)}, 0 <= j < i

这里我们需要用到每个可能的区间中进行一次交易的最大收益,也就是I中的问题。

预先计算出所有的maxprofit的复杂度是O(n^2),dp的复杂度也是O(n^2).

Code:

class Solution {
public:
    int maxProfit(vector<int> &prices) {
        int n = prices.size();
        if(n == 0) return 0;
        vector<vector<int>> dp(n, vector<int>(3,0));
        vector<vector<int>> maxprofit(n, vector<int>(n, 0));
        
        for(int i = 0; i < n; i++)
        {
            int curmin = prices[i];
            int curprofit = 0;
            for(int j = i+1; j < n; j++)
            {
                if(prices[j] < curmin) curmin = prices[j];
                else{
                    int gap = prices[j] - curmin;
                    if(gap > curprofit) curprofit = gap;
                }
                maxprofit[i][j] = curprofit;
                if(i == 0) dp[j][1] = curprofit;
            }
        }
        
        for(int i = 1; i < n; i++)
        {
            int tmp = dp[0][1] + maxprofit[0][i];
            for(int j = 1; j < i; j++)
            {
                if(dp[j][1] + maxprofit[j][i] > tmp) tmp = dp[j][1]+maxprofit[j][i];
            }
            dp[i][2] = tmp;
        }
        
        return dp[n-1][2];
    }
};

 (2)O(n)的解法

参考了这个:http://blog.csdn.net/linhuanmars/article/details/23236995

从上面的分析中我们很容易找出一个case, 例如有一个区间差异特别大,在很长时间内都是最优的选择,而我们的dp却需要不断的枚举一些不可能构成最终解的区间。

怎么样更聪明的定义状态呢?

上一种定义中,我们是定义(i,j)中的最大的解,这样不同的(i,j)对对应的可能是同一种解;这样我们可以用一个global变量来存储;但是由于处理的区间是不断延伸的,后面出现的数字可能和当前末尾的组合起来行程更大的区间,因此我们用一个local变量存储当前以i结尾的最大的解的值。

扩展到能够选择k个区间,我们定义:

global(i,k) 表示截止到第i天,进行k次交易能够获得的最优解(不一定以最后一天结束)

local(i,k) 表示以第i天结束的k次交易能够获得的最优解

能够得到递推式:

local[i][k] = max{global[i-1][k-1], local[i-1][k]} + prices[i] - prices[i-1];

global[i][k] = max{global[i-1][k], local[i][k]};

初始值全为零,最终解为global[n-1][2]。

Code:

class Solution {
public:
    int maxProfit(vector<int> &prices) {
        int n = prices.size();
        if(n == 0) return 0;
        vector<vector<int>> global(n, vector<int>(3,0));
        vector<vector<int>> local(n, vector<int>(3,0));
        
        for(int j = 1; j <= 2; j++)
        {
            for(int i = 1; i < n; i++)
            {
                local[i][j] = max(global[i-1][j-1], local[i-1][j]) + prices[i] - prices[i-1];
                global[i][j] = max(global[i-1][j], local[i][j]);
            }
        }
        return global[n-1][2];
    }
};

 

从其他博客中找到了一种O(n)的解法,思路更简单,但是不具备从2次交易推广到k次的潜力。

主要的思路就是从前往后扫描一遍,找到从0到i的一次交易的最大收益,然后从后往前扫描一遍,得到从i+1到n-1的最大收益。然后两者相加取最大即可。

传送门:http://fisherlei.blogspot.com/2013/01/leetcode-best-time-to-buy-and-sell_3958.html

 

posted @ 2014-10-16 20:14  Avril  阅读(...)  评论(...编辑  收藏