股票交易类问题总结

 

股票交易类问题,要求在一定时间买入,然后卖出,以使利益最大化,通常采用动态规划求解。

1.算法导论第三版投资挥发性公司即最大子数组问题(P39)

首先采用分治法,假定要寻找子数组A[low...high]的最大子数组,利用分治将数组划分为规模尽量相等的子数组A[low...mid],A[mid+1...high]。则A[low...high]的任何连续子数组所处位置必定是以下三种情况之一:

(1)完全位于子数组A[low...mid]中;

(2)完全位于子数组A[mid+1...high]中;

(3)跨越了中点。

前两种情况可以递归求解,关键在于寻找跨越中点的最大子数组,然后在三者中选最大的一个。由于必须跨越中点,所以可以在线性时间求解。代码如下:

int findMaxCrossSubArray(const vector& vs,int lo,int mid,int hi){//寻找跨越中点的最大子数组
    int left_sum=INT_MIN,sum=0;
    for(int i=mid;i>=lo;--i){
        sum+=vs[i];
        if(sum>left_sum)
            left_sum=sum;
    }
    int right_sum=INT_MIN;
    sum=0;
    for(int i=mid+1;i<=hi;++i){
        sum+=vs[i];
        if(sum>right_sum)
            right_sum=sum;
    }
    return left_sum+right_sum;
}
int findMaxSubArray(const vector& vs,int lo,int hi){//求最大子数组
    if(lo==hi)
        return vs[lo];
    else{
        int mid=(lo+hi)/2;
        int left_sum=findMaxSubArray(vs,lo,mid);
        int right_sum=findMaxSubArray(vs,mid+1,hi);
        int cross_sum=findMaxCrossSubArray(vs,lo,mid,hi);
        return max({left_sum,right_sum,cross_sum});
    }
}

其次可以采用动态规划求解:从左到右遍历数组,记录目前为止最大子数组,若sum小于0则sum不可能在最大子数组内,否则去掉sum后的子数组值会更大,矛盾。

int findMaxSubArray2(const vector& vs){
    int max_sum=INT_MIN;
    int sum=0;
    for(int i=0;imax_sum)
            max_sum=sum;
        if(sum<0)
            sum=0;
    }
    return max_sum;
}

2.Best Time to Buy and Sell Stock III

(https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/description/)

首先,定义状态转移方程:

dp[k][i]表示第i天有k份交易的前提下能够获得的最大收益。

则dp[k][i]=max{dp[k][i-1],max{p[i]-p[j]+dp[k-1][j-1] (0<=j<=i)}}

据此,AC代码如下:

class Solution {
public:
    int maxProfit(vector& prices) {
        if(prices.empty())
            return 0;
        int n=prices.size();
        vector> dp(3,vector(n,0));
        for(int k=1;k<=2;++k){
            int m=prices[0];
            for(int j=1;j

在交易只有2份的情况下这种解法空间复杂度是O(n),若交易拓展至k份,则需要调整策略。

3.Best Time to Buy and Sell Stock IV

(https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/description/)

类似问题2,只是观察2中的解法可知,dp中的数据只有k-1和k次时间比i小一的才需要。因此,没有必要划分O(kn)的空间,只需要一个pre存储k-1次的交易,f存储当前交易即可。

class Solution {
public:
    int maxProfit(int k, vector& prices) {
        int n=prices.size();
    if(k==0 || n<2)
        return 0;
    if(k>n/2) k=n/2;
    vector f(n,0);
    vector pre(n,0);
    for(int t=1;t<=k;++t){
        int minv=prices[0];
        for(int i=1;i

4.Best Time to Buy and Sell Stock with Cooldown

(https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/)

这道题没有了交易次数的限制,但加上了冷冻期,即卖掉股票后需要冷冻一天才能再次购买。

可以定义三种状态以便于理解问题:

s0表示冷冻状态,s1表示购买,s2表示抛出股票。

则s0[i]=max(s0[i-1],s2[i-1])

s1[i]=max(s1[i-1],s0[i-1]-prices[i])

s2[i]=s1[i-1]+prices[i]

据此,代码如下:

class Solution {
public:
    int maxProfit(vector& prices) {
        if(prices.empty())
            return 0;
        int n=prices.size();
        vector s0(n,0),s1(n,0),s2(n,0);
        s0[0]=0;
        s1[0]=-prices[0];
        s2[0]=INT_MIN;
        for(int i=1;i

 

你可能感兴趣的:(leetcode)