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

Design an algorithm to find the maximum profit. You may complete at most two transactions.spa

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

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

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

本题有两种解法:htm

(1) blog

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

O(n^2)的解法element

很天然的咱们会想到记录从开头到第i个字符中进行k次交易可以获得的最大收益,记为dp[i][k].leetcode

进行更新: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

相关文章
相关标签/搜索